関数に再割り当てが含まれる場合、一部のコンパイラは関数呼び出しの前にアドレスを保存することがあります。無効なアドレスに格納された戻り値を導きます。
上記の説明で動作を説明する例があります。
#include <stdio.h>
#include <vector>
using namespace std;
vector<int> A;
int func() {
A.Push_back(3);
A.Push_back(4);
return 5;
}
int main() {
A.reserve(2);
A.Push_back(0);
A.Push_back(1);
A[1] = func();
printf("%d\n", A[1]);
return 0;
}
一般的なC++コンパイラがいくつかあり、テスト結果は次のとおりです。
1
5
5
未定義の動作ですか?
この動作は、C++ 17より前のすべてのC++バージョンで未定義です。単純な理由は、代入演算子の両側が任意の順序で評価できることです。
A[1]
_が最初に評価されると仮定すると、その時点でA
の2番目の要素を参照する_int&
_を取得します。func()
が評価されます。これにより、以前に取得した_int&
_をダングリング参照のままにして、ベクトル用のストレージを再割り当てできます。C++ 17でのみ、割り当ての 特別規則2 が作成されました。
すべての単純な割り当て式E1 = E2およびすべての複合割り当て式E1 @ = E2では、E2のすべての値の計算と副作用は、E1のすべての値の計算と副作用の前にシーケンスされます
C++ 17では、func()
の呼び出し後に_A[1]
_を評価する必要があります。これにより、定義済みの信頼できる動作が提供されます。