1

次のクラスのコピーコンストラクター(および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から継承)は、動的に割り当てられたすべてのノードを格納します

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

メインプログラム:

int main()
{
Node *n1 = new Node(5,10,NULL);
Node *n2 = new Node(10,10,NULL);
Node *n3 = new Node(20,10,NULL);
n1->setNode(n2);
n2->setNode(n3);
n3->setNode(n2);
NodesList nl1;
nl1.push_back(n1);
nl1.push_back(n2);
nl1.push_back(n3);
//Copy contructor is used, how to write
NodesList nl2(nl1);
//OPerator = is used, how to write?
NodesList nl3 = nl1;

}

各ノードの浅いコピーではなく、各ノードの深いコピーを作成したいと思います。コピーコンストラクターを使用したサンプルコードをお願いできますか?

各ノードは複数回指定できます。3つのノードn[1]、n [2]、n[3]がNodesListnl1に格納されている場合、このような状況を考えてみましょう。

n[1]はn[2]を指します

n[2]はn[3]を指します

n[3]はn[2]を指します

A]コピーコンストラクターはノードn[1]を処理します。古いオブジェクトn[1]_oldのコピーで表される新しいオブジェクトn[1]_newを作成します。n [1]_oldからポイントされたノードn[2]はまだ存在しないため、n[2]_newも作成する必要があります...n1_newからn2_newへのポインタが設定されます。

B]次に、2番目の点n[2]が処理されます。2回作成することはできません。n[2]_newはA]で作成されました。ただし、指定されたノードn [3]は存在しないため、古いオブジェクトn[3]_oldのコピーとして新しいオブジェクトn[3]_newが作成されます。n2_newからn3_newへのポインタが設定されます。

C]ノードn[3]_newはすでに作成されており、n[2]_newです。n3_newからn2_newへのポインタが設定され、他のオブジェクトは作成されません。

したがって、コピーコンストラクタは、オブジェクトが過去に作成されたかどうかを確認する必要があります...

いくつかの参照カウントが役立つ可能性があります...

4

5 に答える 5

1

問題の私の解決策があります。ノード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::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());
                }
            }
        }
    }
于 2010-03-07T09:27:25.507 に答える
0

標準ライブラリコンテナから継承しないでください(仮想デストラクタがないため)。代わりに、それらをクラスのメンバー変数として含めます。

ディープコピーが必要なので、次のものが必要です:(三つのルール)

Node(Node const& orig): x(orig.x), y(orig.y), n() {
    if (orig.n) n = new Node(*orig.n);
}
Node& operator=(Node const& orig) {
    // The copy-swap idiom
    Node tmp = orig;
    swap(tmp); // Implementing this member function left as an exercise
    return *this;
}
~Node() { delete n; }

より良いアイデアは、ポインタを完全に使用することを避け、ノードを適切なコンテナに入れることです。

于 2010-03-06T11:37:48.917 に答える
0

NodesListの代わりにstd::list<Node>を使用します。さて、コーディングしましょう...

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);
    }
}
于 2010-03-06T11:41:44.757 に答える
0

浅いコピーを実行する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()]);
    }
}

NodeList::operator=(const NodeList&)Tronicと同じコピースワップイディオムを使用できますNode::operator=(const Node&)

NodeListこの設計には、コピーされたものが(最初は)そのノードを参照する唯一の場所であるという点で、潜在的なメモリリークがあります。一時的なものが範囲外になると、実装が不十分だと、含まれているリストNodeListがリークされます。Node

NodeList1つの解決策は、それ自体を宣言することNodeです。( 、&cを介して)Node複数にを追加しない限り、のメソッドは必要に応じてノードを削除できます(たとえば、)。NodeListNodeList::push_backNodeList::operator[]NodeListNodeList::~NodeListNodeList::pop_back

NodeList::~NodeList() {
    Delegate::iterator pnode;
    for (pnode = nodes.begin(); pnode != nodes.end(); ++pnode) {
        delete *pnode;
    }
}

void NodeList::pop_back() {
    delete nodes.back();
    nodes.pop_back();
}

別の解決策は、ではなくスマートポインタNode*を使用することです。共有ポインタNodeListを格納する必要があります。所有権の循環を防ぐための弱いポインタである必要があります。Node::n

于 2010-03-06T23:47:02.250 に答える
0

どうやら、各ノードは同じリスト内の別のノードを指すことだけが許可されていますか?それ以外の場合、リストの「ディープコピー」にはさらに定義が必要です。元のNodeListに接続しないでください。元のノードに接続しないでください。コピーされているリストにないノードのコピーは、他のリストに追加されていますか、それともフリーフローティングですか?

すべてのノード間ポインターがNodeList内に制約されている場合は、ポインターの代わりにインデックスを格納する必要があります。特別な処理は必要ありません。

于 2010-03-06T23:55:30.243 に答える