我发现在以下情况下有一些非常奇怪的行为(在clang和GCC上)。我有一个向量nodes
,其中包含一个元素,即类Node
的一个实例。然后我调用 nodes[0]
上的函数来向向量添加一个新的Node
。当添加新的 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
添加到set()
内部的代码行,则每次输出的X都为3。 - 如果我创建一个新的
Node
并在其上调用它(Node p = nodes[0]
),则输出为3、3、3。 - 如果我创建一个引用
Node
并在其上调用它(Node &p = nodes[0]
),则输出为3、0、0(也许是因为向量重新调整大小时丢失了引用?)
这是由于某种原因导致的未定义行为吗? 为什么?
set()
之前对向量调用了reserve(2)
,那么这将是定义行为。但编写一个类似于set
的函数,要求用户在调用它之前适当地reserve
足够的大小以避免未定义行为是不好的设计,因此不要这样做。 - JohnFilleau