C++ 复制构造函数和动态分配

C++ 复制构造函数和动态分配,c++,operator-overloading,copy-constructor,assignment-operator,C++,Operator Overloading,Copy Constructor,Assignment Operator,我想问您如何为以下类编写复制构造函数(和运算符=) 类节点存储每个节点的坐标x、y和指向另一个节点的指针 class Node { private: double x, y; Node *n; public: Node (double xx, double yy, Node *nn) : x(xx), y(yy), n(nn) {} void setNode (Node *nn) : n(nn) {} ... }; 类NodesList(继承自std::vector)存储所有动态分配的节点

我想问您如何为以下类编写复制构造函数(和运算符=)

类节点存储每个节点的坐标x、y和指向另一个节点的指针

class Node
{
private:
double x, y;
Node *n;

public:
Node (double xx, double yy, Node *nn) : x(xx), y(yy), n(nn) {}
void setNode (Node *nn) : n(nn) {} 
...
};
类NodesList(继承自std::vector)存储所有动态分配的节点

class NodesList : public std::vector<Node *>
{}
}

我不想创建每个节点的浅拷贝,而是创建每个节点的深拷贝。我可以问你一个复制构造函数的示例代码吗

每个节点可以指向多次。让我们假设这样的情况,当3个节点n[1],n[2],n[3]存储在节点列表nl1中时:

n[1]指向n[2]

n[2]指向n[3]

n[3]指向n[2]

A] 我们的复制构造函数处理节点n[1]。它创建一个新对象n[1]\u new,由旧对象n[1]\u old的副本表示。从n[1]\u old指向的节点n[2]仍然不存在,因此还必须创建n[2]\u new。。。设置从n1_new到n2_new的指针

B] 然后处理第二点n[2]。不能创建两次,n[2]_new是在A]中创建的。但是点节点n[3]不存在,因此创建新对象n[3]\u new作为旧对象n[3]\u old的副本。设置了从n2_new到n3_new的指针

C] 节点n[3]\u已新建,n[2]\u已新建。已设置从n3_new到n2_new的指针,并且不会创建其他对象

所以复制构造函数应该检查对象是否在过去创建过


一些引用计数可能会有帮助…

您不应该从标准库容器继承(因为它们缺少虚拟析构函数)。相反,将它们作为成员变量包含在类中

既然你想要一份深度拷贝,你需要这些:(三法则)


更好的办法可能是避免完全使用指针,而只是将节点放在合适的容器中。

不应从标准库容器继承(因为它们缺少虚拟析构函数)。相反,将它们作为成员变量包含在类中

既然你想要一份深度拷贝,你需要这些:(三法则)

更好的办法可能是避免完全使用指针,而只是将节点放在合适的容器中。

我只使用std::list而不是NodesList。好吧,让我们编码

NodesList::NodesList(const NodesList& source)
{
    const_iterator e = source.end();
    for (const_iterator i = source.begin(); i != e; ++i) {
        Node* n = new Node(**i);
        push_back(n);
    }
}
我只会使用std::list而不是NodesList。好吧,让我们编码

NodesList::NodesList(const NodesList& source)
{
    const_iterator e = source.end();
    for (const_iterator i = source.begin(); i != e; ++i) {
        Node* n = new Node(**i);
        push_back(n);
    }
}

NodeList::NodeList(const NodeList&)
中执行浅层复制,您就不必担心周期会破坏复制操作。免责声明:以下内容未经测试,不完整,可能存在漏洞

class NodeList {
private:
    typedef std::vector<Node*> Delegate;
    Delegate nodes;

public:
    NodeList(int capacity=16) : nodes() { nodes.reserve(capacity); }

    NodeList(const NodeList& from);
    virtual ~NodeList();

    NodeList& operator=(const NodeList& from);

    /* delegated stuff */
    typedef Delegate::size_type size_type;
    typedef Delegate::reference reference;
    typedef Delegate::const_reference const_reference;
    typedef Delegate::iterator iterator;
    typedef Delegate::const_iterator const_iterator;

    size_type size() const { return nodes.size(); }

    iterator begin() { return nodes.begin(); }
    const_iterator begin() const { return nodes.begin(); }
    iterator end() { return nodes.end(); }
    const_iterator end() const { return nodes.end(); }
    // ...
};

NodeList::NodeList(const NodeList& from)
    : nodes(from.size()), flags(NodeList::owner)
{
    std::map<Node*, Node*> replacement;
    Delegate::const_iterator pfrom;
    Delegate::iterator pto;
    // shallow copy nodes
    for (pfrom=from.begin(), pto=nodes.begin(); 
         pfrom != from.end(); 
         ++pfrom, ++pto) 
    {
        replacement[*pfrom] = *pto = new Node(**pfrom);
    }
    // then fix nodes' nodes
    for (pto = nodes.begin(); pto != nodes.end(); ++pto) {
        (*pto)->setNode(replacement[(*pto)->getNode()]);
    }
}

另一种解决方案是使用,而不是
节点*
<代码>节点列表应存储<代码>节点::n应该是防止所有权循环的一种方法。

节点列表::节点列表(const NodeList&)
中执行浅层复制,您不必担心循环会破坏复制操作。免责声明:以下内容未经测试,不完整,可能存在漏洞

class NodeList {
private:
    typedef std::vector<Node*> Delegate;
    Delegate nodes;

public:
    NodeList(int capacity=16) : nodes() { nodes.reserve(capacity); }

    NodeList(const NodeList& from);
    virtual ~NodeList();

    NodeList& operator=(const NodeList& from);

    /* delegated stuff */
    typedef Delegate::size_type size_type;
    typedef Delegate::reference reference;
    typedef Delegate::const_reference const_reference;
    typedef Delegate::iterator iterator;
    typedef Delegate::const_iterator const_iterator;

    size_type size() const { return nodes.size(); }

    iterator begin() { return nodes.begin(); }
    const_iterator begin() const { return nodes.begin(); }
    iterator end() { return nodes.end(); }
    const_iterator end() const { return nodes.end(); }
    // ...
};

NodeList::NodeList(const NodeList& from)
    : nodes(from.size()), flags(NodeList::owner)
{
    std::map<Node*, Node*> replacement;
    Delegate::const_iterator pfrom;
    Delegate::iterator pto;
    // shallow copy nodes
    for (pfrom=from.begin(), pto=nodes.begin(); 
         pfrom != from.end(); 
         ++pfrom, ++pto) 
    {
        replacement[*pfrom] = *pto = new Node(**pfrom);
    }
    // then fix nodes' nodes
    for (pto = nodes.begin(); pto != nodes.end(); ++pto) {
        (*pto)->setNode(replacement[(*pto)->getNode()]);
    }
}

另一种解决方案是使用,而不是
节点*
<代码>节点列表应存储<代码>节点::n应该是一个,以防止所有权循环。

显然,每个节点只允许指向同一列表中的另一个节点?否则,列表的“深度副本”需要更多的定义。它是否应该连接到原始节点列表?它是否应该连接到任何原始节点?不在被复制列表中的节点的副本是否添加到其他列表或自由浮动


如果所有节点到节点的指针都限制在节点列表中,那么您可能应该存储索引而不是指针,那么不需要特殊处理。

显然,每个节点只允许指向同一列表中的另一个节点?否则,列表的“深度副本”需要更多的定义。它是否应该连接到原始节点列表?它是否应该连接到任何原始节点?不在被复制列表中的节点的副本是否添加到其他列表或自由浮动


如果所有节点到节点的指针都被约束在节点列表中,那么也许您应该存储索引而不是指针,那么就不需要进行特殊处理。

我有解决问题的方法。添加了存储节点n的新版本的新数据成员n_ref:

class Node
{
private:
double x, y;
Node *n, *n_ref;

public:
Node (double xx, double yy, Node *nn) : x(xx), y(yy), n(nn) {n_ref = NULL;}
Node * getNode() {return n;}
Node * getRefNode () {return n_ref;}
void setNode (Node *nn) {this->n = nn;} 
void setRefNode (Node *nn) {this->n_ref = nn;}
复制构造函数创建节点的浅层副本:

Node (const Node *node) 
{
    x = node->x;
    y = node->y;
    n = node->n;
    n_ref = node->n_ref;
}
节点列表的复制构造函数

    NodesList::NodesList(const NodesList& source)
    {
        const_iterator e = source.end();
        for (const_iterator i = source.begin(); i != e; ++i) {

            //Node* n = new Node(**i);

            //Node n still has not been added to the list
            if ((*i)->getRefNode() == NULL)
            {
                //Create node
                Node *node = new Node(*i);

                //Add node to the list
                push_back(node);

                //Set this note as processed
                (*i)->setRefNode(node);

                //Pointed node still has not been added to the list
                if ((*i)->getNode()->getRefNode() == NULL)
                {
                    //Create new pointed node
                    Node *node_pointed = new Node ((*i)->getNode());

                    //Add node to the list
                    push_back(node_pointed);

                    //Set pointer to n
                    node->setNode(node_pointed);

                    //Set node as processed
                    ((*i)->getNode())->setRefNode(node_pointed);
                }

                //Pointed node has already been added to the list
                else
                {
                    //Set pointer to node n
                    node->setNode((*i)->getRefNode());
                }
            }

            //Node n has already been added to the list
            else
            {
                //Get node
                Node * node = (*i)->getRefNode();

                //Pointed node still has not been added
                if ((*i)->getNode()->getRefNode() == NULL)
                {
                    //Create new node
                    Node *node_pointed = new Node ((*i)->getNode());

                    //Add node to the list
                    push_back(node_pointed);

                    //Set pointer to n
                    node->setNode(node_pointed);

                    //Set node as processed
                    ((*i)->getNode())->setRefNode(node_pointed);
                }

                //Pointed node has already been added to the list
                else
                {
                    //Set pointer to n
                    node->setNode((*i)->getNode()->getRefNode());
                }
            }
        }
    }

这是我解决这个问题的办法。添加了存储节点n的新版本的新数据成员n_ref:

class Node
{
private:
double x, y;
Node *n, *n_ref;

public:
Node (double xx, double yy, Node *nn) : x(xx), y(yy), n(nn) {n_ref = NULL;}
Node * getNode() {return n;}
Node * getRefNode () {return n_ref;}
void setNode (Node *nn) {this->n = nn;} 
void setRefNode (Node *nn) {this->n_ref = nn;}
复制构造函数创建节点的浅层副本:

Node (const Node *node) 
{
    x = node->x;
    y = node->y;
    n = node->n;
    n_ref = node->n_ref;
}
节点列表的复制构造函数

    NodesList::NodesList(const NodesList& source)
    {
        const_iterator e = source.end();
        for (const_iterator i = source.begin(); i != e; ++i) {

            //Node* n = new Node(**i);

            //Node n still has not been added to the list
            if ((*i)->getRefNode() == NULL)
            {
                //Create node
                Node *node = new Node(*i);

                //Add node to the list
                push_back(node);

                //Set this note as processed
                (*i)->setRefNode(node);

                //Pointed node still has not been added to the list
                if ((*i)->getNode()->getRefNode() == NULL)
                {
                    //Create new pointed node
                    Node *node_pointed = new Node ((*i)->getNode());

                    //Add node to the list
                    push_back(node_pointed);

                    //Set pointer to n
                    node->setNode(node_pointed);

                    //Set node as processed
                    ((*i)->getNode())->setRefNode(node_pointed);
                }

                //Pointed node has already been added to the list
                else
                {
                    //Set pointer to node n
                    node->setNode((*i)->getRefNode());
                }
            }

            //Node n has already been added to the list
            else
            {
                //Get node
                Node * node = (*i)->getRefNode();

                //Pointed node still has not been added
                if ((*i)->getNode()->getRefNode() == NULL)
                {
                    //Create new node
                    Node *node_pointed = new Node ((*i)->getNode());

                    //Add node to the list
                    push_back(node_pointed);

                    //Set pointer to n
                    node->setNode(node_pointed);

                    //Set node as processed
                    ((*i)->getNode())->setRefNode(node_pointed);
                }

                //Pointed node has already been added to the list
                else
                {
                    //Set pointer to n
                    node->setNode((*i)->getNode()->getRefNode());
                }
            }
        }
    }

但是有一个小问题。每个节点可以指向多次。使用上述复制构造函数会产生重复的对象。n1->setNode(n2);n3->setNode(n2);节点n2将被创建两次……我不认为节点构造函数做不了什么。我想,由于容器拥有关于链结构的所有可用数据,它可以分析节点并建立类似的结构。我担心,上面编写的复制构造函数会创建重复的对象。。。它不会检查指向的对象n是否仍然没有创建或已经。。。在任何情况下都会创建指向对象。但有一个小问题。每个节点可以指向多次。使用上述复制构造函数会产生重复的对象。n1->setNode(n2);n3->setNode(n2);节点n2将被创建两次……我不认为节点构造函数做不了什么。我想,由于容器拥有关于链结构的所有可用数据,它可以分析节点并建立类似的结构。我担心,上面编写的复制构造函数会创建重复的对象。。。它不会检查指向的对象n是否仍然没有创建或已经。。。在任何情况下都会创建指向对象。
setNode
的定义不合法。只有构造函数才能在