【问题标题】:c++ push_back copying object instead of referencec++ push_back 复制对象而不是引用
【发布时间】:2016-05-17 19:21:59
【问题描述】:

我在理解以下 cmets 中提到的问题时遇到了一些问题:

class Node {
    public:
        Node(int value): value(value), neighbors() {}
        int value;
        std::vector<std::shared_ptr<Node>> neighbors;
};

    std::vector<Node> nodes;
    nodes.reserve(50);
    for(int j = 0 ; j < 50; ++j) {
        nodes.push_back(Node(j));
    }
    for(int j = 1 ; j < 25; ++j) {
        nodes.at(0).neighbors.push_back(std::make_shared<Node>(nodes.at(j)));
    }

    //The following line is copying nodes.at(0) instead of just 
    //copying a reference to nodes.at(0). Why?
    nodes.at(15).neighbors.push_back(std::make_shared<Node>(nodes.at(0)));

    for(int j = 25 ; j < 50; ++j) {
        nodes.at(0).neighbors.push_back(std::make_shared<Node>(nodes.at(j)));
    }

    std::cout << nodes.at(15).neighbors.at(0).neighbors.size();
    //Prints out 24

    std::cout << nodes.at(0).neighbors.size();
    //Prints out 49

为什么下面的行复制nodes.at(0)(它返回对节点向量第一个元素的引用)而不是存储对它的引用?

    nodes.at(15).neighbors.push_back(std::make_shared<Node>(nodes.at(0)));

【问题讨论】:

  • 这就是它应该工作的方式。顺便说一句:为了让您的问题更准确,请查看 push_backmake_shared 是否实际上复制了您的节点。
  • 你怎么知道它被复制了?您知道std::make_shared&lt;Node&gt; 将创建一个Node 实例,并调用新对象copy-constructor 以使用来自nodes.at(0) 的节点对其进行初始化?是你说的复制构造吗?
  • 你知道std::make_shared 是做什么的吗?
  • 见这里:en.cppreference.com/w/cpp/memory/shared_ptr/make_sharedThis function is typically used to replace the construction std::shared_ptr&lt;T&gt;(new T(args...))
  • 请注意,如果您打算在此之后向nodes 添加更多节点,则根本无法存储指向节点的指针!那是因为vector 被允许分配新的Nodes,将旧的复制/移动到新的,然后删除旧的,任何指向旧的指针都会失效。

标签: c++ pointers vector shared-ptr


【解决方案1】:
// The following line is copying nodes.at(0) instead of just 
nodes.at(15).neighbors.push_back(std::shared_ptr<Node>(&nodes.at(0))); 

// Notice I didn't call make_shared, because make_shared woul allocate anew Node,
// but you already have allocated your node in your nodes vector (which is global).

// 24 as expected
std::cout << nodes.at(0).neighbors.size() << std::endl;
// 24 as well
std::cout << nodes.at(15).neighbors.at(0)->neighbors.size() << std::endl;

//Insert another element
nodes.at(0).neighbors.push_back(std::make_shared<Node>(nodes.at(30)));

// 25 as expected
std::cout << nodes.at(0).neighbors.size() << std::endl;
// 25 as well
std::cout << nodes.at(15).neighbors.at(0)->neighbors.size() << std::endl;

如果我正确理解了您的问题,请告诉我。

您可以改为使用std::vector&lt;std::shared_ptr&lt;Node&gt;&gt;,然后直接推送

nodes.at(15).neighbors.push_back(nodes.at(0));

使用共享 ptr 向量的另一种解决方案是:

std::vector<std::shared_ptr<Node>> nodes;
nodes.reserve(50);

for (int j = 0; j < 50; ++j)
    nodes.push_back(std::make_shared<Node>(j));

for (int j = 1; j < 25; ++j)
    nodes.at(0)->neighbors.push_back(nodes.at(j));

nodes.at(15)->neighbors.push_back(nodes.at(0));

// 24 as expected
std::cout << nodes.at(0)->neighbors.size() << std::endl;
// 24 as well
std::cout << nodes.at(15)->neighbors.at(0)->neighbors.size() << std::endl;

//Insert another element
nodes.at(0)->neighbors.push_back(nodes.at(30));

// 25 as expected
std::cout << nodes.at(0)->neighbors.size() << std::endl;
// 25 as well
std::cout << nodes.at(15)->neighbors.at(0)->neighbors.size() << std::endl;

【讨论】:

    【解决方案2】:

    您的代码中没有任何内容存储引用。您的代码复制了一个节点,因为您在 std::make_shared 中分配了一个新节点并调用了复制构造函数。

      std::vector<Node> nodes;
    

    它在您的函数中是本地的。不可能保留指针(共享或不共享)或对该向量元素的引用。或许您想改用共享指针向量:

     std::vector<std::shared_ptr<Node>> nodes;
    

    请记住,shared_ptr 在存在循环引用时无法正常工作。如果您的数据结构是通用图,那么 shared_ptr 可能不适合存储邻居。您可能需要考虑使用weak_ptr(您必须分别保存一个指向所有节点的共享指针容器)。

    【讨论】:

      【解决方案3】:

      Vector 始终存储副本。您可以在这里找到更多信息 : Is std::vector copying the objects with a push_back?

      【讨论】:

      • 在这种情况下不相关,因为有问题的向量存储 std::share_ptr 对象。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      • 2011-01-17
      • 1970-01-01
      • 1970-01-01
      • 2014-07-11
      • 1970-01-01
      • 2011-02-07
      相关资源
      最近更新 更多