次の状況で、(clangおよびGCCで)非常に奇妙な動作が見つかりました。nodes
クラスのインスタンスである1つの要素を持つベクトルがありますNode
。次に、ベクターにnodes[0]
新しい関数を追加する関数を呼び出しますNode
。新しいノードが追加されると、呼び出し元オブジェクトのフィールドがリセットされます!ただし、関数が終了すると、通常の状態に戻ります。
これは最小限の再現可能な例だと思います:
#include <iostream>
#include <vector>
using namespace std;
struct Node;
vector<Node> nodes;
struct Node{
int X;
void set(){
X = 3;
cout << "Before, X = " << X << endl;
nodes.push_back(Node());
cout << "After, X = " << X << endl;
}
};
int main() {
nodes = vector<Node>();
nodes.push_back(Node());
nodes[0].set();
cout << "Finally, X = " << nodes[0].X << endl;
}
どの出力
Before, X = 3
After, X = 0
Finally, X = 3
Xがプロセスによって変更されないままであることを期待しますが。
私が試した他のこと:
Node
inside を追加する行を削除すると、set()
毎回X = 3が出力されます。- 新規に作成して
Node
それを呼び出すと(Node p = nodes[0]
)、出力は3、3、3になります。 - 参照を作成
Node
してその(Node &p = nodes[0]
)で呼び出すと、出力は3、0、0になります(おそらく、ベクトルのサイズが変更されると参照が失われるためです)。
これは何らかの理由で未定義の動作ですか?どうして?
reserve(2)
呼び出す前にベクトルにset()
これを行動に定義されます。しかし、set
そのような関数を書くことは、reserve
未定義の動作を避けるために呼び出す前に適切な十分なサイズをユーザーに要求することは悪い設計なので、それを行わないでください。