如果乙個建構函式的第乙個引數是自身類型別的引用,且任何額外引數都沒有預設值,則此建構函式是拷貝建構函式。(《c++primer,第五版》)
class foo
;
類的成員中有指標時,使用深拷貝。
#include using namespace std;
class foo
foo(const foo&)= default; //拷貝建構函式
foo& operator=(const foo&) = default; //拷貝賦值運算子
int* pint;
};//淺拷貝,foo1和foo2中的pint指向同一塊記憶體位址
foo foo1;
foo foo2(foo1);
//深拷貝
class cop
cop(const cop& cop)
int* pint;
};//深拷貝,cop1和cop2中pint指向不同記憶體
cop cop1;
cop cop2(cop1);
在某些情況下(函式返回物件引用),物件拷貝後立即就被消耗了。拷貝構造就回造成效能上的浪費,而且深拷貝也會造成浪費。移動構造可以避免這種情況的發生。
為了支援移動構造,c++11引入了右值引用。
右值引用:必須繫結到右值的引用,通過&&來獲得右值引用,類似左值引用(常規引用),右值應用也是一塊記憶體的別名。
右值:字面常量、在表示式求值過程中臨時建立的物件,這些使用過後就被銷毀的資源。不同於左值的持久狀態。
因此,右值引用只能繫結到將要被銷毀的物件上,左值引用只能繫結到持久的物件上。
//例子**於 《c++primer 第五版》
int i = 42;
int& r = i; //正確,i是左值
int&& rr = i; //錯誤
int& r2 = i * 42; //錯誤,i*42是右值,用完即銷毀
const int& r3 = i * 42; //正確,隱式轉換為左值後,r3引用
int&& rr2 = i * 42; //正確,繫結右值
int&& rr1 = 42; //正確,字面常量是右值
int&& rr2 = rr1; //錯誤,rr1左值
變數都是左值,因此無法將右值引用繫結到乙個右值引用型別的變數上。
如果要將右值引用繫結到左值上,可以通過move函式來獲得左值的右值引用型別。對乙個左值呼叫move函式後,除了對該左值賦值和銷毀外,不再使用它。
int i = 42;
int&& rr = move(i);
//i和rr引用同一塊記憶體
i = 32;
cout << i << endl;
cout << rr << endl;
移動建構函式依靠右值引用特性來將來改變記憶體的管理者,而不同於拷貝構造對記憶體進行拷貝。
移動構造:第乙個引數是該類型別的乙個右值引用,且任何額外的引數都必須有預設實參。使用移動建構函式必須確保銷毀移後源物件是無害的(不會重複釋放同一塊記憶體)。
cop(cop&& cop) noexcept : pint(cop.pint)
cop& operator=(cop&& cop) noexcept
cop retcop()
//呼叫移動賦值運算子,cop3中pint接管retcop返回物件中的pint指向記憶體
cop cop3 = retcop();
noexcept承諾函式不丟擲異常,標準庫對這個函式不做額外處理。 C 移動建構函式和拷貝建構函式
我們用物件 a初始化物件b 後物件 a我們就不在使用 了,但是物件a的空間還在呀 在析構之前 既然拷貝建構函式,實際上就是把a物件的內容複製乙份到b中,那麼為什麼我們不能直接使用a的空間呢?這樣就避免了新的空間的分配,大大降低了 構造的成本 這就是移動建構函式設計的初衷 拷貝建構函式 中,對於指標,...
C 中的拷貝構造,賦值和移動構造
在說明這幾個名詞時,我們需要定義乙個測試類person,person類的測試環境為vs2013 一般情況下,在物件宣告時用拷貝建構函式對物件進行初始化 在編譯器進行優化的時候也會使用移動構造函 數 在有臨時物件產生的情況下 這樣效率會高一些,如避免深度拷貝之類的操作 一旦初始化之後,在 進行 運算將...
c 11 移動構造 移動賦值 拷貝構造
最近對準備深入學習一下c 11所有的新特性,今天研究了一下c 11的std move和std forward,在研究這個的時候,需要對c 0xx的拷貝構造,拷貝賦值有一些了解.這個不知道的自己去了解,這裡記錄一下c 11新加的移動版本 移動構造 移動賦值和拷貝構造 拷貝賦值的比較,文章引用 現代c ...