0

だから、私が書いているリンクリストクラスで operator= をオーバーライドしようとしていますが、何らかの理由でこの奇妙な問題が発生し続けています。

List& List::operator=(const List& copyList){
if(copyList.head != nullptr){
    makeEmpty();   // clears *this from any previous nodes
    cout << "if statement " << endl;
    head = new Node; // create a new node for head
    head -> data = copyList.head -> data; // copy the first data of copylist
    Node* pnew = head; // a temp node to traverse the new linkedlist
    assert(head != nullptr);
    Node* current2 = copyList.head;
    current2 = current2 -> next;
    while(current2 != NULL && pnew != NULL){
        cout << "entering while loop " << endl;
        pnew-> next = new Node;
        pnew -> next->data = current2 ->data;
        cout << "pnew next data " << *(pnew -> next->data)  << endl;
        assert(pnew-> next != nullptr);
        pnew = pnew -> next;
        current2 = current2 -> next;
        cout << "after current2" << endl;
    }
     pnew -> next = NULL;

}else{
    cout << "else statement " << endl;
    head = nullptr;
}
cout<< "printing out copylist"<< endl << copyList << endl;
cout<< "printing current list: " << endl << *this << endl;
return *this;

}

したがって、これは演算子のオーバーライドをテストするために必要なコードです。

cout << "mylist:" << endl << mylist << endl;
   cout << "mylist4:" << endl << mylist4 << endl;
   mylist = mylist4;
   cout << "mylist:" << endl;
   cout << mylist << endl;
   cout << "mylist4:" << endl;
   cout << mylist4 << endl;

これは出力です:

mylist:
10 f
16 u
20 n
25 !

mylist4:
14 s
15 t
16 u
18 f
19 f
25 !

if statement
entering while loop
pnew next data 15 t

after current2
entering while loop
pnew next data 16 u

after current2
entering while loop
pnew next data 18 f

after current2
entering while loop
pnew next data 19 f

after current2
entering while loop
pnew next data 25 !

after current2
printing out copylist
14 s
15 t
16 u
18 f
19 f
25 !

printing current list:
14 s
15 t
16 u
18 f
19 f
25 !
*crashes right here*

私はこの問題を約3日間理解しようとしています。どんな助けでも大歓迎です。前もって感謝します!

EDIT:コンストラクターは次のとおりです(デストラクタはコンパイラによるデフォルトのものです):

NodeData::NodeData(int n, char c)  { 
    num = n; ch = c; 
} 

EDIT2:慎重に調べた結果、問題が見つかりました。問題は、while ループの後の head の最後のノードである pnew を null にポイントしなかったことです。これで問題は解決しました。皆様のご支援に感謝いたします。

4

2 に答える 2

2

あなたはあなたの Node クラスを制御できます。それは、透過的に、または必要に応じて自分の手で、コピー構築および代入演算子をサポートする必要があります。それを考えると、コピー-ctor/swap/destructor メカニズムを利用することが理想的なアプローチであるという Dietmar に同意します。

これを手作業で行いたい場合は、次の方法が 1 つの方法です。あなたの実装は、これを必要以上に難しくしています

List& List::operator=(const List& copyList)
{
    List tmp;
    Node **dst = &tmp.head;
    const Node* src = copyList.head;
    while (src)
    {
        *dst = new Node(*src);     // invoke Node copy-ctor
        src = src->next;           // advance source
        (*dst)->next = nullptr;    // break link to original next
        dst = &(*dst)->next;       // move target to next pointer
    }

    // tmp now has a copy of the source list
    //  swap its head pointer with ours.
    std::swap(tmp.head, head);

    // upon return, the tmp object that now holds our
    //  original list will clean it up. we own the
    //  new list form this point on. 
    return *this;
}

使い方

ポインタ ツー ポインタdstは、常に、新しいノードが取り込まれる次のポインタのアドレスを保持します。最初は、ローカルList tmpオブジェクトのヘッド ポインターのアドレスを保持します。. nextノードを追加すると、最後に追加されたノードのポインターのアドレスを常に保持するように更新されます。これを行うことで、自動的にフォワード チェーンを取得します。コピーが完了すると、tmpはソースの複製になります。次に、ヘッド ポインターを独自のものと交換します。これにより、誰がどのリストを所有しているかが入れ替わります。tmpfunction-exit で破棄されると、古いリストが破棄されます。headポインターが指す新しいリストを保持します。

上記は、デフォルトの copy-ctor of を使用していることを前提としています。つまり、コピーを作成すると、データ値Node次のリンクの両方がコピーされます。後者は必要ないため、埋め込まれたリンク ブレークが発生します。コピー後にリンクを常に NULL に設定するように実際に実装すると、リンク切れを解消できます。つまり、コピー コンストラクターは次のようになります。Node::Node(const Node&)Node

Node::Node(const Node& arg)
    : data(arg.data)
    , next()
{
}

これにより、元の次のポインターdataへの偶発的なリンクがなく、クリーンな (コピーできる限りクリーンな) コピーが保証されます。arg

そうは言っても、Dietmarの答えは最も正しいので、それに応じて投票しました. これが役立つ場合は、賛成票を投じることを検討してください。ただし、彼は簡単に理想的なソリューションです.

于 2013-10-26T19:23:21.353 に答える
2

実装を詳しく調べずに (代入演算子が正当な理由なしに強力な例外セーフにならないことを確認したときに停止しましたmakeEmpty()): 代入演算子を実装する最も簡単な方法は、コピー コンストラクターを活用することです。デストラクタであり、関数を書くのは一般的に簡単swap()です。クラス名を除いて、実装はすべてのクラスで同じに見えます。

T& T::operator= (T other) {
    other.swap(this);
    return *this;
}

引数を値で渡すのは意図的なものであることに注意してください。これは、値が実際に発生する場所です。それによるコピーと比較しT const&て、場合によっては実際のコピーを省略できるという利点があります。

于 2013-10-26T19:04:58.700 に答える