2012-10-29 37 views
16

我很困惑移動構造函數被調用時與複製構造函數。 我讀過以下來源:何時移動構造函數被調用?

Move constructor is not getting called in C++0x

Move semantics and rvalue references in C++11

msdn

所有這些來源要麼過於複雜(我只想要一個簡單的例子),或者只顯示如何編寫移動構造函數,而不是如何調用它。我寫了一個簡單的問題更具體:

const class noConstruct{}NoConstruct; 
class a 
{ 
private: 
    int *Array; 
public: 
    a(); 
    a(noConstruct); 
    a(const a&); 
    a& operator=(const a&); 
    a(a&&); 
    a& operator=(a&&); 
    ~a(); 
}; 

a::a() 
{ 
    Array=new int[5]{1,2,3,4,5}; 
} 
a::a(noConstruct Parameter) 
{ 
    Array=nullptr; 
} 
a::a(const a& Old): Array(Old.Array) 
{ 

} 
a& a::operator=(const a&Old) 
{ 
    delete[] Array; 
    Array=new int[5]; 
    for (int i=0;i!=5;i++) 
    { 
     Array[i]=Old.Array[i]; 
    } 
    return *this; 
} 
a::a(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
} 
a& a::operator=(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
    return *this; 
} 
a::~a() 
{ 
    delete[] Array; 
} 

int main() 
{ 
    a A(NoConstruct),B(NoConstruct),C; 
    A=C; 
    B=C; 
} 

當前A,B和C都有不同的指針值。我希望A有一個新的指針,B有C的舊指針,C有一個空指針。

有點偏離主題,但如果有人可以建議一個文檔,我可以詳細瞭解這些新功能,我將不勝感激,可能不需要問更多的問題。

+0

在部分相關的問題,你可能要檢查的複製和交換成語http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom您assignement運營商。 – undu

+0

[相關FAQ](http:// stackoverflow。com/questions/3106110 /) – fredoverflow

回答

22

一招調用構造函數:

  • 當一個對象初始化爲std::move(something)
  • 當一個對象初始化爲std::forward<T>(something)T不是左值的引用類型(「完美的模板編程有用轉發「)
  • 當一個對象初始化器是一個臨時的,並且編譯器不會完全消除拷貝/移動
  • 通過返回值的函數,局部類對象時,編譯器不消除複製/移動完全
  • 投擲功能本地類對象時,編譯器不消除複製/移動完全

這不是一個完整的列表。請注意,如果參數具有類類型(不是引用),則「對象初始值設定項」可以是函數參數。

a RetByValue() { 
    a obj; 
    return obj; // Might call move ctor, or no ctor. 
} 

void TakeByValue(a); 

int main() { 
    a a1; 
    a a2 = a1; // copy ctor 
    a a3 = std::move(a1); // move ctor 

    TakeByValue(std::move(a2)); // Might call move ctor, or no ctor. 

    a a4 = RetByValue(); // Might call move ctor, or no ctor. 

    a1 = RetByValue(); // Calls move assignment, a::operator=(a&&) 
} 
4

首先,你的拷貝構造函數壞了。從對象複製和複製到對象都將指向相同的Array,並且在它們超出範圍時都將嘗試delete[],從而導致未定義的行爲。要修復它,請複製數組。現在

a::a(const a& Old): Array(new int[5]) 
{ 
    for(size_t i = 0; i < 5; ++i) { 
    Array[i] = Old.Array[i]; 
    } 
} 

,在不進行移動的賦值,因爲你希望它是,因爲這兩個賦值語句是由左值分配的,而不是使用右值。對於要執行的移動,您必須從右值移動,或者它必須是可以將左值視爲右值的上下文(例如函數的返回語句)。

爲了得到想要的效果,使用std::move來創建一個右值引用。

A=C;    // A will now contain a copy of C 
B=std::move(C); // Calls the move assignment operator 
+0

'B = std :: move(C); //調用複製賦值運算符'它不應該是移動賦值運算符嗎?之後,C可能不再是過去的樣子。 – RainingChain

+0

@RainingChain是的,這是一個錯字,謝謝! – Praetorian