0

単純な「ノード」クラスの C++ コードを書いています。これは基本的に、線形リンク リストを管理するために使用されるクラスです。私は通常これを構造体で実行しますが、OOP とクラスをより適切に処理しようとしています。Nodeクラスについてこれまでに得たものは(注:Stringクラスは、典型的な「文字列」クラスの私のバージョン(トリミング)であり、コピーコンストラクタ、割り当てオーバーロード、デストラクタなどを実装しています。テストでは、うまく機能し、完全に自己完結しているようです):

class Node {
public:

    //Constructor
    //-----------

    Node() : next_(0) {} //inline (String constructor called)

    //Destructor
    //----------

    ~Node(); 

    //Copy Constructor
    //----------------

    Node(const Node &);    

    //Operator Overload: =
    //---------------------
    //In conjunction with copy constructor.  Protects Class.

    Node & operator=(const Node &);   

private:

    String relatedEntry_;
    Node * next_;
};

1 つのインスタンスの作成は正常に機能しますが (つまりNode node;、)、コピー コンストラクターを呼び出すインスタンスを作成すると、プログラムの最後でセグメンテーション違反が発生します。リンクされたリストとクラスに構造体を使用することの違いは、私には少しトリックであり、ここで何か重要なものが欠けていると思います。デフォルト コンストラクター、コピー コンストラクター、およびオーバーロードされた代入演算子の実装を次に示します。

//Constructor inlined

//Destructor
Node::~Node()
{
    Node * curr = next_;
    while (curr) //cycle through LL and delete nodes
    {
        Node * temp = curr; //hold onto current
        curr = curr->next_; //increment one
        delete temp; //delete former current
    }
}


//Copy Constructor
Node::Node(const Node & cp)
{
    std::cout << "in CopyCon" << std::endl;
    relatedEntry_ = cp.relatedEntry_; //calls String class copy constructor/assignment overload
    Node * curr = cp.next_; //for clarity, for traversal
    while (curr) //copies related entry structure
    {
        Node * oldNext = next_;
        next_ = new Node;
        next_->next_ = oldNext; //'next' field (assign prior)
        next_->relatedEntry_ = curr->relatedEntry_; //String class copy
        curr = curr->next_; //increment
    }
}


//OO:  =
Node & Node::operator=(const Node & cp)
{
    std::cout << "in OO: =" << std::endl;
    if (this == &cp)
        return *this; //self assignment
    delete next_; //delete LL
    relatedEntry_ = cp.relatedEntry_; //String Class Assignment Overload
    Node * curr = cp.next_; //for clarity, for traversal
    while (curr)
    {
        Node * oldNext = next_; //hold onto old
        next_ = new Node; 
        next_->next_ = oldNext; //set next to old
        next_->relatedEntry_ = curr->relatedEntry_; //set this string to cp string
        curr = curr->next_; //increment
    }
    return *this;
}

オーバーロードされた割り当て関数を使用すると、実質的に同じコードであっても正常に動作するように見えることに注意してください (セグメンテーション違反はありません) 。割り当てが行わ れる前に両方のオブジェクトが既に初期化されているという事実に関係していると思いますか?

//This seems to work ok
Node node1;
Node node2;
node2 = node1;

私はこのバグで数時間過ごしたので、少し休まなければなりません。これについての洞察をいただければ幸いです。ありがとう。

4

2 に答える 2

1

コピーコンストラクタループには、次の行があります。

Node * oldNext = next_;

ただし、ループの最初のラウンドでは、の値はnext_何でも可能であり、ほとんどの場合そうではありませんNULL。これは、最後のノードにnull以外のポインターがあることを意味します。

NULLループの前に初期化すると、機能するはずです。

于 2012-07-31T07:15:11.690 に答える
1

リストとノードの概念が混同されています。ノードのシーケンスを管理する List クラスを作成する必要があります。Node デストラクタは多かれ少なかれ List デストラクタがどのように見えるべきかということです。Node 自体はデストラクタを必要としません。

具体的に間違っているのは、これを書いたときに Node デストラクタが再帰的に自分自身を呼び出し、ノードdelete temp;の残りのシーケンスを削除しますが、Node デストラクタがループしてそれらを再度削除しようとすることです。

于 2012-07-31T07:37:39.787 に答える