26

C++ では、以下に示すように、からへの変換が可能な場合に、char**を受け入れる関数に引数としてa を渡すことができないのはなぜですか?const char**char*const char*

void f1(const char** a)
{

}

void f2(const char* b)
{

}

int main(int argc, char const *argv[])
{
   char* c;

   f1(&c); // doesn't work
   f2(c); //works

   return 0;
}

コンパイラ出力は

test.cpp: 関数 'int main(int, const char**)' 内:
test.cpp:15:10: エラー: 'char**' から 'const char**' への無効な変換 [-fpermissive]
test.cpp:1:6: エラー: 'void f1(const char**)' の引数 1 を初期化しています [-fpermissive]
4

1 に答える 1

26

ポインターの逆参照の両方のレベルでコンテンツを保護する必要があります。これによりconst char**、最初の逆参照で実際にコンテンツを変更できます。

char *tmp = "foo"; //Deprecated but it's ok for the example
void f1(const char** a)
{
  a[0] = tmp;     //this is legal
  a[0][1] = 'x';  //this is not
}

そして、これはおそらく意図したものではありません。次のようになります。

char *tmp = "foo"; //Deprecated but it's ok for the example
void f1(char const* const* a)
{
  a[0] = tmp;    // this is not legal any more
  a[0][1] = 'x'; // this still upsets compiler
}

コンパイラは、このような「部分的に」保護されたポインター型への暗黙的な変換を許可しません。このような変換を許可c++faqすると、@zmb のコメントで指摘されているように、厄介な結果が生じる可能性があります。この回答では、例を使用して、許可されている場合にオブジェクトのconstnessに違反する方法についても言及していますchar

ただし、2番目のコード例に示すように、「完全に」保護されたポインターに暗黙的に変換できるため、以下のコードがコンパイルされます。

void f1(char const* const* a){}
void f2(const char* b){}
int main(int argc, char const *argv[])
{
   char* c;
   f1(&c); // works now too!
   f2(c);  // works
   return 0;
}

実際、この問題についてはたくさんの質問と回答が横たわっています。例えば:

  1. 「char**」から「const char**」への無効な変換</a>
  2. 'float**' を 'const float**' に変換するときにエラーが発生するのはなぜですか?

編集: 最初の例を少し間違えました。ご指摘ありがとうございます!

于 2013-08-16T12:57:08.620 に答える