2010-03-09

C++相談室での素晴らしい疑問

C++相談室 part78

696 名前:デフォルトの名無しさん[sage] 投稿日:2010/03/09(火) 07:26:55
通らない
ttp://codepad.org/d4Wo3ozT

int main()
{
    int ** pp = nullptr ;

    int * const * const pcpc = pp ; // これはコンパイルが通る。

    int const ** cpp = pp ;// エラー。なんで?
}

これは、規格の4.4 Qualification conversions [conv.qual]によって、明示的に禁止されている。何故か。これを許可してしまうと、C++の型システムのconst性に、穴が生じるのだ。

int main()
{
    // i は書き換えられない。
    int const i = 0 ;

    int * p ;

    // もちろんこれはエラー
    p = &i ;

    int const **  cpp = &p ; // もし、これが許可されているとする。

    // *cppは、pである。pはiへのポインタを持つようになる。
    *cpp = &i;

    // pはiを参照しているので、pを経由して、constであるはずのiを書き換えられる。
    *p = 123 ;
}

つまり、この標準変換を認めてしまうと、暗黙のうちに、const性を破ることができてしまうのだ。

もし、何らかの理由で、どうしても、このような型変換を行いたい場合は、const_castをするしかない。

int ** pp = nullptr ;
int const ** cpp = const_cast<int const **>(pp) ;// OK。ただし自己責任。

ちなみに、const性を破らないことが保証できれば、キャストはできる。つまり、以下のようなことはできる。

int ** pp = nullptr ;
int const * const * cpcp = pp ;

int i = 0 ;
// エラー
*cpcp = &i ;

なぜなら、*cpcpの型は、int const * constなので、参照先のポインタを変更することはできないからだ。これによってconst性は守られるので、暗黙なキャストも許可されている。

2 comments:

萌ゑ said...

何か現行の標準C++にも似たような事があったような無かったような
その場合の動作は未定義 undefined とされていました
つまり鼻から悪魔ですね

江添亮 said...

この部分は、C++98の頃から変わっていないはずですが。