【问题标题】:C++ Vector not changing value after being altered in a methodC++向量在方法中被改变后不改变值
【发布时间】:2023-03-26 01:08:02
【问题描述】:

我正在尝试为有向图中的节点创建一个类(我对它们了解不多,如果我搞砸了任何术语,请原谅)。 每当我将指向 n2 的指针添加到 n1 的 outNodes 向量时,我希望将指向 n1 的指针添加到 n2 的 inNodes 向量。我希望这是有道理的,这是我的代码。

#include <iostream>
#include <vector>

class Node {
private:
  static int nextId;
  int id;
  std::vector<Node*> ptr_outNodes;
  std::vector<Node*> ptr_inNodes;
public:
  Node() {
    id = nextId++;
  }

  int getId() {
    return id;
  }

  void setInNodes(Node n) {
    ptr_inNodes.push_back(&n);
  }
  void setOutNodes(Node n) {
    ptr_outNodes.push_back(&n);
    n.setInNodes(*this);
  }

  std::vector<Node*> getOutNodes() {
    return ptr_outNodes;
  }

  std::vector<Node*> getInNodes() {
    return ptr_inNodes;
  }
};

int Node::nextId = 0;


int main() {
  Node n1;
  Node n2;

  n1.setOutNodes(n2);
  std::cout << n2.getInNodes().size();
  return 0;
}

如您所见,我已将其设置为返回 n2 的 inNodes 的大小。当我运行程序时,我看到它的大小为 0。如果我在 setInNodes 方法中打印出大小,我得到的结果 1 对我来说很奇怪。另外,如果我将主要功能更改为:

int main() {
  Node n1;
  Node n2;

  n1.setOutNodes(n2);
  n2.setInNodes(n1);
  std::cout << n2.getInNodes().size();
  return 0;
}

我得到结果 1。添加该行表明该函数正在工作,所以我相信当我从 setOutNodes() 调用 setInNodes() 时出现问题。过去半小时我一直在盯着这个,所以如果有人可以帮助我,那就太好了,谢谢!

【问题讨论】:

  • setInNodessetOutNodes都推送了传值的函数参数的地址,所以是原始的副本,在函数结束时超出范围。这是未定义的行为。您的两个get* 函数也都按值返回向量,因此是另一个副本。这不一定是问题,但您确实需要注意这一点,以防您尝试getOutNodes().push_back(whatever) 之类的东西并想知道为什么原始向量没有改变。
  • @RetiredNinja 那么我应该尝试将引用存储在向量中吗?
  • 你应该做的是充分学习和理解:1)通过值传递参数与通过引用传递参数之间的区别,以及2)在自动和动态范围内声明的对象之间的区别。两者都是对象如何在 C++ 中工作的基本核心原则,必须完全理解这个主题。对这些核心主题的完整讨论不能用 Stackoverflow 上的一两句话来完全概括,而是每本 C++ 教科书中多个章节的主题,您可以在其中查找更多信息和详细解释。
  • void addInNode(Node* node) 实际上&amp;n 获取堆栈上复制的节点结构的地址,这会给出危险的悬空指针。

标签: c++ vector nodes


【解决方案1】:

您正在为方法setInNodessetOutNodes 提供原始Node 对象的副本。您推入向量中的指针是该副本的地址,而不是原始对象的地址。

要推送原始 Node 对象的地址,您需要将 Node 指针传递给函数。

代码:

... // Your Node class code

void setInNodes(Node *n) {
  ptr_inNodes.push_back(n);
}
void setOutNodes(Node *n) {
  ptr_outNodes.push_back(n);
  n.setInNodes(this);
}
...

// in the main function:
n1.setOutNodes(&n2);
n2.setInNodes(&n1);

【讨论】:

    【解决方案2】:

    在您的代码中:

    void setInNodes(Node n) {
        ptr_inNodes.push_back(&n);
      }
      void setOutNodes(Node n) {
        ptr_outNodes.push_back(&n);
        n.setInNodes(*this);
      }
    

    您正在按值传递Node(它是临时的)。然后,您将指向临时变量的指针添加到您的向量中。当您的函数 (setxxx) 超出范围时,临时对象被销毁,因此存储的指针是指向无效对象的指针。在函数退出后访问/取消引用指针是未定义的行为(即程序可以做任何事情)。

    正如在别处提到的,您可以传入指针或引用。

    void setXxNode(Node& node)...
    

    通过引用传递是我的选择,因为它需要一个值(显示意图)。然后将引用的地址添加到向量中,但请注意,引用的对象的生命周期必须超过现在持有指针的对象的生命周期。

    【讨论】:

      猜你喜欢
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 2021-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多