指针向量的复制构造函数

Posted

技术标签:

【中文标题】指针向量的复制构造函数【英文标题】:Copy constructor for a vector of pointers 【发布时间】:2016-05-07 19:48:39 【问题描述】:

我正在尝试创建一个包含指针向量的节点类。这是我的代码:

node.h:

#ifndef NODE_H
#define NODE_H

class node

public:
    vector<node*> next;
    void add_arc(node & a)

    string some_string;

#endif

node.cpp:

void node::add_arc(node & a)

    node *b = &a;
    next.push_back(b);       //only copyies nodes

ma​​in.cpp:

int main()

    vector<node> nodes;
    node a;
    node b;
    node c;

    a.somestring = "a";
    b.somestring = "b";
    c.somestring = "c";



    a.add_arc(b);      //a should point to b
    a.add_arc(c);      //a should point to c

    nodes.push_back(a);
    nodes.push_back(b);
    nodes.push_back(c);

    cout << nodes[0].next.size() << endl;           // prints "2", works fine
    cout << nodes[0].next[0]->some_string << endl;  //empty

我认为这就像重载 push_back 一样简单:

void push_back(vertex * pointer)

    next.push_back(pointer);

但我认为我确实需要一个复制构造函数或其他一些方法来完成这项工作。我将如何为指针向量执行此操作?

编辑:我想我没有很好地解释它。看看这个问题的答案: Segmentation fault when accessing a pointer's member function in a vector 将“a”作为参考对我不起作用

【问题讨论】:

阅读第二章智能指针 为什么要一个连续的容器存储节点?为什么next 应该是std::vector&lt;Node*&gt; cout &lt;&lt; nodes[0].next[0]-&gt;some_string &lt;&lt; endl; //empty 好吧,你没有在这段代码中将字符串设置为任何值,所以它是空的 问题是 add_arc 中的参数被破坏了,即使有引用,字符串最终也是空的。智能指针真的是最好的方法吗?另外@milleniumbug 我将字符串编辑为具有值,它们最终仍然为空 我看不出有任何失败的原因,实际上是it works for me(如果我把你的代码变成minimal reproducible example 并修复语法错误)。 【参考方案1】:

它有效...

您的代码按预期生成正确的输出(请参阅online demo):

2
b

...但是这种设计不是面向未来的

但是这个结果在某种程度上与运气有关,因为在你的代码 sn-p:

nodes 向量中的节点是原始对象的副本,包括它们的所有指针 这些指针指向的局部对象 a、b、c 仍然存在

但是,在更复杂的代码中,您很快就会得到悬空指针。 想象一下:

错误示例 1:您创建了一个图形,将所有节点直接保存在节点向量中。然后在节点之间添加第一条弧。一旦您将新节点添加到向量中,可能会发生重新分配,并且您可能会看到所有 next 指针无效。 错误示例 2:您像以前一样初始化图形,但在 main 调用的函数中。在这种情况下,一旦您从此函数返回,所有本地节点都会被销毁,并且向量的节点将指向不再存在的对象。保证UB!

如何改进?

您的设计未能识别所有节点都属于同一个图。

有一个快速而肮脏的出路:总是从免费存储中创建节点,并将它们存储在vector&lt;node*&gt; 中。

vector<node*> nodes;
node *a = new node("a");  // Imagine a node constructor 
node *b = new node("b");
a->add_arc(b);            //change signature, to accept a pointer 
nodes.push_back(a);
nodes.push_back(b);

有一个更好的方法:进一步改进以前的方法,但使用shared_ptr&lt;node*&gt; 确保不再引用的节点(既不是由节点向量,也不是由弧)自动销毁。

还有一个更好的方法:将节点封装在一个表示图形的类中。在这种情况下,您可以考虑使用vector&lt;nodes&gt; 并将next 中的指针替换为向量中目标节点的索引。没有指针,但完美的图形副本会容易得多。并且没有更多的内存管理麻烦。

class node    // just to give the general idea

public:
    vector<int> next;  // not usable without the graph 
    void add_arc(int a)
    string id;
;

class graph 
    vector<node> nodes; 
public:  
    void add_node (node a);  
    void add_arc (string from, string to);  
    node& operator[] (size_t i); 
    ...
; 

【讨论】:

以上是关于指针向量的复制构造函数的主要内容,如果未能解决你的问题,请参考以下文章

调整动态分配的指针数组的大小(复制构造函数不起作用?)

何时删除复制构造函数

如何获得指向类的复制构造函数的成员函数指针?

是否为数组/向量插入调用了赋值运算符或复制构造函数?

对复制构造函数已被删除的对象向量进行迭代 (C2280)

复制构造函数 C++ 没有正确复制指针