タイトルが分かりにくくてすみません。以下のページであるコードが議論されています。
http://forums.topcoder.com/?module=Thread&threadID=673205&start=0&mc=13
そのコードは次のようになっています。一部コメントを加えました。
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
struct XYZ { int X,Y,Z; };
vector<XYZ> A;
int rec(int idx){
int i = A.size();
A.push_back(XYZ());
if (idx >= 1000) return i;
A[i].X = rec(idx+1);
/*
以下のように書き換えると、実行結果は正しくなる
int x = rec(idx+1);
A[i].X = x;
*/
return i;
}
int main(){
A.clear();
rec(0);
printf("A :");
for (int i=0; i<5 && i<(int)A.size(); i++)
printf(" %d",A[i].X);
puts("");
fflush(stdout);
}
これを手元の環境(Windows7)で実行してみると、
g++(MinGW)で実行するとクラッシュします。
Visual C++ 2010 Express の cl でコンパイルすると、実行結果は次のようになります。
A : 1 2 3 4 5
上のページを読むと(読み間違っているかも知れませんが)、評価順序に関係が
あるようなのですが…。英語があまりうまく読めないこともあり、
上のページの内容が理解できずにいます。
なぜクラッシュするのでしょうか?
リンク先をちょこっと読んだ上でのものなので、違っているかもしれせん。
クラッシュする原因は、A[i]の評価とrecの呼び出し順序の問題になると思います。
・A[i]よりも先にrecの呼び出しがあった場合
問題は起きない
・recの呼び出しより先にA[i]が評価された場合
recの中のpush_backの呼び出しにより、評価されたA[i]の参照が無効化されるので、クラッシュの可能性がある。
ということでしょう。
前者は、
> A[i].X = rec(idx+1);
は、
int _tempX = rec(idx+1);
XYZ& _tempXYZ = A[i];
_tempXYZ.X = _tempX;
であり、後者は、
XYZ& _tempXYZ = A[i];
int _tempX = rec(idx+1);
_tempXYZ.X = _tempX;
なのだと思います。
# XYZ * const _tempXYZ = &A[i];とした方が問題がわかりやすいかもしれません。
なかなか、説明するのが難しいですが……。
YuOさん、ありがとうございます。
なるほど、あ、そうか、push_back()の呼び出しが後になると、メモリの移動が
発生する(かもしれない)からなんですね。
ということは、予めreserve()で必要サイズを確保すれば問題は発生しなくなる
ということですよね? (なぜなら、push_back()呼び出しによるサイズの増加に
対して、メモリの移動が起こらなくなるから)。
実際に、A.reserve(10000)を前もって呼び出しておくと、今度は
クラッシュしなくなりました。