2014-02-13 49 views
1

我新的C++ 11和寫了下面的代碼來了解std::move是如何工作的:瞭解移動構造函數,的std ::移動和析構函數

#include <queue> 
#include <stdio.h> 

class X { 
public: 
    X(int x) : x_(x) {} 
    ~X() { 
    printf("X(%d) has be released.\n", x_); 
    } 

    X(X&&) = default; 
    X& operator = (X&&) = default; 

    X(const X&) = delete; 
    X& operator = (const X&) = delete; 
private: 
    int x_; 
}; 


int main() { 
    std::queue<X> xqueue; 
    for (int x = 0; x < 5; ++x) { 
    xqueue.push(std::move(X(x))); 
    } 
    return 0; 
} 

但是,它會生成以下的輸出,這表明每個X(n)的析構函數已被調用兩次:

X(0) has be released. 
X(1) has be released. 
X(2) has be released. 
X(3) has be released. 
X(4) has be released. 
X(0) has be released. 
X(1) has be released. 
X(2) has be released. 
X(3) has be released. 
X(4) has be released. 

我可以想像第二輪的輸出發生在右功能main()的端部,並且所述第一輪可能發生在循環時,這些中間X超出範圍。

但是,我認爲這樣的中間產品X的所有權將完全轉移到隊列中,並且不應在其所有權轉移期間調用它們的析構函數。

所以我的問題是:

  1. 當我看到被釋放兩次的情況下,這是否意味着它執行復制而不是移動?
  2. 如果上面的答案是肯定的,那麼我怎樣才能真正避免複製?

謝謝

回答

4

如果從一個物體轉移到另一個物體,你還有總共兩個對象。它們都需要被銷燬。也許move是一個稍有誤導的術語,但它不是從一個地方移動到另一個地方的對象本身(對象從不實際移動) - 它是對象的內容。

  1. 不可以。如上所述,移動並不會消失其中一個對象。複製和從一個對象移動到另一個對象都會涉及兩個對象。不同之處在於它們對物體有什麼影響。當然,副本會將一個對象的成員複製到另一個對象的成員。另一方面,移動會將成員從一個對象移到另一個對象 - 通常是一個更快的操作。
  2. N/A
+0

因此,如果我的對象有成員指針,並且它的析構函數將釋放這些指針。這是否意味着我無法真正移動這些對象? – keelar

+1

@keelar你可以 - 當你從它移動時,只需設置指向'nullptr'的指針。在空指針上執行delete操作將不起作用。在實現移動構造函數/賦值運算符時,應該使對象保持有效(但不確定)狀態。 –

+0

非常感謝!這聽起來很完美。我能否進一步知道'= default'移動構造函數/賦值是否將'nullptr'賦值給源成員指針?或者我應該開發自己的移動構造函數/任務? – keelar

1

此舉構造竊取的對象的屬性/成員並將其提供給新的對象。因此,在您的示例中,第一組刪除語句在移動構造函數的作用域結束並且現在對象被銷燬時發生。

和第二組DELETE語句的時候出現在隊列中新創建的對象被銷燬

另外值得注意的是,如果被刪除的對象的屬性不是POD類型,那麼它是不是一個好想法訪問他們在刪除方法否則會導致段故障