【问题标题】:c++ vector of struct initc++向量的struct init
【发布时间】:2018-08-22 11:38:45
【问题描述】:

我是 C++ 新手,我正在尝试将结构向量初始化为以下代码。

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 并将其推入向量中。但我后来发现存在一个问题,即 a 总是在完全相同的内存位置创建。因此,应该指向每个 Node 本身的 p 将指向循环后的最后一个元素。有人可以解释为什么节点 a 总是在相同的内存地址创建以及如何解决这个问题?

【问题讨论】:

  • 这让我很想知道 push_back 操作中发生了什么。

标签: c++ pointers vector struct


【解决方案1】:

您有未定义的行为,因为您没有为您的 Node 类定义自定义复制构造函数。

disjointSet.push_back(a); 复制a。这是使用默认的复制构造函数,它只是对所有成员变量进行逐元素复制。所以在副本中,p 指向的是原来的Node 的地址,而不是它本身。但是当循环迭代结束时,Node 被销毁,因此指针不再有效。它依赖于实现,但很常见的是循环碰巧在每次循环中为a 使用相同的堆栈内存,因此所有元素中的p 都指向同一个地址,这不再是有效的@987654329 @。

你需要定义一个拷贝构造函数,将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;
}

【讨论】:

  • 您还应该实现一个复制赋值运算符,其编译器生成的实现也存在与编译器生成的复制构造函数相同的成员复制问题,因此如果不是,则会错误地设置p覆盖:Node&amp; Node::operator=(const Node &amp;rhs) { if (&amp;rhs != this) { x = rhs.x; rank = rhs.rank; } return *this; }
  • @RemyLebeau 谢谢,补充说使用另一个问题的成语。
  • 除非您实现自己的忽略pswap 重载,否则通用swap 将复制p,这是您在这种情况下不想要的。 swap xrank 成员单独使用,或者根本不使用 swap
  • @RemyLebeau 你是对的,通用方法不适用于此。
【解决方案2】:

您的节点是在堆栈上创建的。并且在构造函数内部分配的地址指向堆栈。如果您希望Nodes 是一个在将它们移动/复制到容器中时不会改变的常量地址,您需要对它们进行堆分配并使用节点指针向量。例如。 vector&lt;std::unique_ptr&lt;Node&gt;&gt;

【讨论】:

    【解决方案3】:

    您没有使用堆内存。存储局部变量的地址并尝试在其他地方访问它是 UB。如果我是对的,那么对于“为什么”循环的每次迭代都采用相同的内存空间的答案是实现定义的,在这种情况下,它是在重用相同的堆栈空间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      相关资源
      最近更新 更多