最近、厄介なシュレディンバグに出くわしました。ファイルをフラット メモリ表現にロードしようとしているときに、作成者は次のようなコードを記述していました。
class Line final { public:
int stuff[3];
char* data;
}
//...
Line* line = /*...*/;
//Trying to treat line->data like an array. This is *wrong*.
line->data = reinterpret_cast<char*>(line) + 3*sizeof(int);
//...
line->data[0] = /*...*/
line->data[1] = /*...*/
//...
line->data[n] = /*...*/ //"line->data" changes because of this line!
したがって、何が起こっているかというと、コードの最初の行は基本的に にline->data
等しく設定されてい&line->data
ます。が指している値を変更すると、それ自体が指している値line->data
も変更される可能性があるため、これは誤りです。line->data
その時、問題が発生するまでに非常に長い時間がかかったことが不思議に思いました。私の理解では、restrict
(または g++/MSVC で__restrict
)修飾されていない限り、コンパイラはポインターがエイリアスされていると想定する必要があります。したがって、line->data[0]
何かに設定すると、次のアクセスで表示され、line->data[1]
ほぼ確実に無効になります。ただし、デバッガーでは、変更はかなり後になるまで表示されず、書き込みはしばらくの間順調に続きました。
コンパイラ (この場合は MSVC 2013) は、セルフエイリアスが可能であるとは考えていなかったと思います。それは許されますか?