2017-09-14 85 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

使用複製語義實現移動賦值操作符是錯誤的。這打破了移動語義學的所有好處。如果你打算這樣做,你可以直接實現一個拷貝賦值操作符。我給你的代碼不應該輸出'1 2 3 4 5',如果它給了'6 7 8 9 10'。如果您在移動分配後獲得'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包含已刪除的節點,並且在開始循環時執行失敗。你想要做的就是在刪除它們之前從列表中刪除節點。

去會的方式:

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

而且有這樣的方法:

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

。當然pop定義取決於你的全面落實之類的。如果你正在存儲指向給你的對象的指針,你可能不應該刪除它們。但是,如果您使用的是額外的包裝,例如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

這就是它,我意識到我的錯誤,並更新了迴應! :) –