我是C ++的新手,我正在尝试将struct的向量初始化为下面的代码。
struct Node{
int x;
Node *p;
int rank;
Node(int x) {
this->p = this;
this->x = x;
this->rank = 0;
}
};
int main() {
vector<Node> disjointSets;
for (int i = 0; i < 50; i++) {
Node a(i);
disjointSets.push_back(a);
}
}
在main中,我尝试每次创建一个Node a并将其推送到vector中。但我后来发现有一个问题,即a始终在完全相同的内存位置创建。因此,应该指向每个节点本身的p将指向循环之后的最后一个元素。有人可以解释为什么Node a总是在相同的内存地址创建,以及如何解决这个问题?
答案 0 :(得分:1)
您有未定义的行为,因为您尚未为Node
类定义自定义副本构造函数。
disjointSet.push_back(a);
制作了a
的副本。这是使用默认的复制构造函数,它只是完成所有成员变量的元素副本。因此,在副本中,p
指向原始Node
的地址,而不是其本身。但是当循环迭代结束时,Node
被销毁,因此指针不再有效。它依赖于实现,但很常见的是,每次循环时,循环恰好使用相同的堆栈内存a
,因此所有元素中的p
指向同一个地址,不再是有效的Node
。
您需要定义一个复制构造函数,将p
设置为副本的地址:
Node(const Node &oldnode) {
p = this;
x = oldnode.x;
rank = oldnode.rank;
}
和复制赋值运算符:
Node& operator=(const Node &oldnode) {
if (&oldnode != this) {
x = oldnode.x;
rank = oldnode.rank;
}
return *this;
}
答案 1 :(得分:0)
您没有使用堆内存。存储本地变量的地址并尝试在其他地方访问它是UB。如果我是正确的,答案为&#34;为什么&#34;循环的每次迭代采用相同的内存空间是实现定义的,在这种情况下,它重用相同的堆栈空间。
答案 2 :(得分:0)
您的节点是在堆栈上创建的。并且在构造函数内分配的地址指向堆栈。如果你希望Node
是一个在移动/复制到容器时不会改变的常量地址,你需要堆分配它们并使用一个Node指针向量。例如。 vector<std::unique_ptr<Node>>
。