在以下情况下,我发现了一些非常奇怪的行为(在clang和GCC上)。我有一个向量,nodes
有一个元素,一个class的实例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
在调用它之前有足够大的大小,以避免未定义的行为,这是不好的设计,所以不要这样做。