2017-09-14 16 views
0

移動代入演算子に何が間違っているのかわかりません。ここに関数があります。移動代入演算子C++

virtual LinkedList<T> &operator=(LinkedList<T> &&other) 
{ 
    cout << " [x] Move *assignment* operator called. " << endl; 

    // Delete our own elements 
    ListNode<T> *temp1 = _front; 
    while (temp1 != nullptr) 
    { 
     ListNode<T> *n = temp1->getNext(); 
     delete temp1;   
     temp1 = n; 
    } 
    // Grab other data for ourselves 
    ListNode<T> *temp2 = other._front; 
    while (temp2 != nullptr) 
    { 
     addElement(temp2->getValue()); 
     temp2 = temp2->getNext(); 
    } 
    // Reset their pointers to nullptr 

    other._front = nullptr; 
    other._end = nullptr; 
    other._size = 0; 
    other._last_accessed_index = 0; 
    other._last_accessed_node = nullptr; 

    return *this; 
} 

テストコード - これは私の先生のテストです)私は、テストを実行したとき、私はランダムな負の数を取得するので、私は、データを正しくつかむいないと思うと、」あなたがしているプログラムが動作を停止しましたコード - 。

// Use move *assignment* operator 
cout << " [x] Test #5: Move *assignment* constructor behavior" << endl; 
moved1 = LinkedList<int>{ 6, 7, 8, 9, 10 }; 
cout << " [x] Result:" << endl; 
cout << " [x] Expected:\t6 7 8 9 10" << endl; 
cout << " [x] Actual:\t\t"; 
for (int i = 0; i < moved1.getSize(); i++) 
{ 
    cout << moved1.getElementAt(i) << " "; 
} 
cout << endl << endl; 

これが移動し、移動代入演算子を扱う初めてです感謝:)

+0

コードをステップ実行したときにデバッガに表示される内容は何ですか? –

+0

それはすべて実行されますが、テストコードを実行すると、リスト内のデータを受信しようとすると壊れます@KenWhite –

+0

テストコードを投稿できますか?問題の最も小さなサブセットを投稿できますか? – norlesh

答えて

1

これは、移動割り当て演算子の適切な実装ではありません。それはコピー代入演算子のように見えますが(メモリをリークするので、良いものではありません)。

#include <utility> 

LinkedList<T>& operator=(LinkedList<T> &&other) 
{ 
    cout << " [x] Move *assignment* operator called. " << endl; 

    std::swap(_front, other._front); 
    std::swap(_end, other._end); 
    std::swap(_size, other._size); 
    std::swap(_last_accessed_index, other._last_accessed_index); 
    std::swap(_last_accessed_node, other._last_accessed_node); 

    return *this; 
} 

移動代入演算子は解放しないでください:

典型的な移動代入演算子は、より多くの代わりに次のようになります。 ソースのコンテンツの所有権をターゲットオブジェクトに移動し、その逆も同様です。ソースオブジェクトが代入演算子の終了後に破壊されたときにソースオブジェクトがターゲットオブジェクトの以前の内容を解放しましょう、そうクラスはまた、適切なデストラクタの実装を持っていることを確認してください:良い測定のために

~LinkedList() 
{ 
    // Delete our elements 
    ListNode<T> *temp = _front; 
    while (temp != nullptr) 
    { 
     ListNode<T> *n = temp->getNext(); 
     delete temp;   
     temp = n; 
    } 
} 

、ここで何コピーですコンストラクタ、コンストラクタを移動し、代入演算子は、次のようになりコピー:

LinkedList() : 
    _front(nullptr), 
    _end(nullptr), 
    _size(0), 
    _last_accessed_index(0), 
    _last_accessed_node(nullptr) 
{ 
    cout << " [x] Default *constructor* called. " << endl; 
} 

LinkedList(const LinkedList<T> &src) 
    : LinkedList() 
{ 
    cout << " [x] Copy *constructor* called. " << endl; 

    ListNode<T> *temp = src._front; 
    while (temp != nullptr) 
    { 
     addElement(temp->getValue()); 
     temp = temp->getNext(); 
    } 
} 

LinkedList(LinkedList<T> &&src) 
    : LinkedList() 
{ 
    cout << " [x] Move *constructor* called. " << endl;  
    src.swap(*this); 
} 

LinkedList(initializer_list<T> src) 
    : LinkedList() 
{ 
    cout << " [x] Initialization *constructor* called. " << endl; 

    const T *temp = src.begin(); 
    while (temp != src.end()) 
    { 
     addElement(*temp); 
     ++temp; 
    } 
} 

LinkedList<T>& operator=(const LinkedList<T> &other) 
{ 
    cout << " [x] Copy *assignment* operator called. " << endl; 

    if (&other != this) 
     LinkedList<T>(other).swap(*this); 

    return *this; 
} 

LinkedList<T>& operator=(LinkedList<T> &&other) 
{ 
    cout << " [x] Move *assignment* operator called. " << endl; 
    other.swap(*this);   
    return *this; 
} 

void swap(LinkedList<T> &other) 
{ 
    std::swap(_front, other._front); 
    std::swap(_end, other._end); 
    std::swap(_size, other._size); 
    std::swap(_last_accessed_index, other._last_accessed_index); 
    std::swap(_last_accessed_node, other._last_accessed_node); 
} 

コピーをと代入演算子を移動するには、実際の値で入力オブジェクトを取得し、するかどうかをコンパイラが決定させることにより、単一の実装にマージすることができますそのオブジェクトを初期化するときに、コピーまたは移動セマンティクスを使用します。オペレータが呼び出されるコンテキスト:

LinkedList<T>& operator=(LinkedList<T> other) 
{ 
    cout << " [x] *assignment* operator called. " << endl; 
    swap(other); 
    return *this; 
} 
+0

あなたが追加したすべてのため、本当にありがとう!この練習では、「移動代入演算子」は、移動代入演算子が「コピー」メソッドを使用して何を行うかをシミュレートすると考えられます。現時点では、私のコードは10 9 8 7 6が必要なときに1 2 3 4 5を出力しています。もしこれを明確にすることができれば、大いに感謝します。 –

+0

もう一度、すべてのこの情報をありがとう、私はすべての概念を理解するのに困っていた:) –

+0

コピーのセマンティクスを使用して移動代入演算子を実装するのは間違っています。これは、移動セマンティクスの利点のすべてを奪うものです。これを行う場合は、コピー代入演算子を単独で実装することもできます。私が与えたコードは '6 7 8 9 10'と指定されていれば' 1 2 3 4 5'を出力してはいけません。あなたが移動割り当ての後に '1 2 3 4 5'を得ているなら、あなたは何か間違っています。 –

0

これは、残りのコードを持たずに必ずするのは難しいが、それはあなたがしているように見えます割り当てられているリストが正しくクリアされません。

あなたは:

// Delete our own elements 
ListNode<T> *temp1 = _front; 
while (temp1 != nullptr) 
{ 
    ListNode<T> *n = temp1->getNext(); 
    delete temp1;   
    temp1 = n; 
} 

あなたが実際にthisから要素を削除されていません。そのため、moved1には削除されたノードが含まれており、ループを開始すると実行が失敗します。あなたがしたいのは、削除する直前にリストからノードを削除することです。

だろう行く方法:popの定義は、クラスのあなたの完全な実装に依存します。もちろん

void pop() // removes the first element from the list 
{ 
    _front = _end._front; 
    _end = _end._end; 
    --_size; 
} 

// Remove our own elements 
ListNode<T> *temp1 = _front; 
while (temp1 != nullptr) 
{ 
    ListNode<T> *n = temp1->getNext(); 
    pop(); 
    delete temp1;   
    temp1 = n; 
} 

とのような方法があります。あなたに与えられたオブジェクトへのポインタを格納している場合は、それらを削除しないでください。しかし、ListNodeのような追加のラッパーを使用している場合は、popメソッドで削除する必要があります。ただし、ラッパーの場合は、ポインタをまったく使用しない方が良いでしょう。

詳細についてはstd::list::pop_frontをご覧ください。

+0

あなたの応答に感謝します!あなたが示唆したようにコードを実行すると、リストには数字1 2 3 4 5 6 7 8 9 10があり、10 9 8 7 6の出力が必要ですが、今すぐ出力は1 2 3 4 5 –

+0

ですそれはremoveElementAtがすでにそれを削除するためですか?この場合、移動代入演算子で再度削除する必要はありません。 – Flynsee

+0

それはまさにそれ、私は間違いを認識し、応答を更新! :) –

関連する問題