最近在看c++ primer的時候,對於物件移動一直不太懂,所以在查詢各種資料,仔細研究**後,打算寫篇部落格記錄下來,果然還是不要得過且過,看見不懂的就查,弄懂為止最好了。很多時候都會發生物件拷貝,但是拷貝有個問題,對於有些僅僅做完拷貝就銷毀的情況,其實沒必要,更好的做法是進行移動元素;在新標準中,可以用容器儲存不可拷貝的型別,前提是他能被移動即可;
標準庫容器、string和shared_str類既支援移動也支援拷貝,io類和 unique _xstr 類可以移動但不能拷貝;
右值引用只能繫結到乙個將要銷毀的物件,通過 && 來獲得右值引用;
右值引用:所引用的物件將要被銷毀;物件沒有其他使用者;這些意味著右值引用的**可以自由的接管所引用的物件的資源;
變數是左值,因此我們不能將乙個右值引用直接繫結到乙個變數上,但是常量可以,即使變數是右值引用型別也不可以;
例子:
int && rr1 = 42; //正確:字面意思是右值
int && rr2 = rr1; //錯誤:表示式rr1是左值
呼叫了move函式就意味著承諾,不能對移動後對源物件的值做任何的假設,但是你可以銷毀,也可以賦予它新值,就是不能使用乙個移後源物件的值;
使用move的**應該使用std:move而不是簡單的move,這樣做可以避免潛在的名字衝突;
例子:
int && rr3 = std::move(rr1);
和拷貝建構函式不同,移動建構函式不分配任何記憶體,在完成資源移動後,移動建構函式還需要確保移後源物件是否可以銷毀掉,其必須不再指向被移動的資源,因為其資源的所有權已經歸屬到新建立的物件(如果物件中存在成員指標,則需要將其置為空);
例子:
derived::derived(derived && d) noexcept: tag(d.tag)
其中tag是derived的成員屬性;
noexcept 是我們承諾乙個函式不丟擲異常的一種方法,在乙個建構函式中,noexcept出現在引數列表和初始化列表開始的冒號之間(在類的宣告和定義中都需要指定noexcept);
(使用方法如上)
不能在使用右側運算物件的資源之前就釋放左側運算物件的資源;在移動操作之後,移後源物件必須保持有效的、可析構的狀態,但是客戶不能對其進行任何假設;
例子:
derived& operator=(const derived& other)
return *this;
}
注意:函式引數是引用型別的
和拷貝構造操作不同,如果乙個類定義了自己的拷貝建構函式,拷貝賦值函式或者析構函式,編譯器就不會為它合成移動建構函式和移動賦值運算子,則其就會使用拷貝操作替代移動操作;
只有當乙個類沒有定義任何自己版本的拷貝控制成員,而且它的所有資料成員都能移動構造或移動賦值時,編譯器才會為它合成移動建構函式和移動賦值運算子;
和拷貝操作不同,移動操作永遠不會隱式定義為刪除的函式;
合成的移動操作定義為刪除的函式遵循定義刪除的合成拷貝類似原則:
下面這種情況是正確的,沒有定義為刪除的情況:
class x ;
class hasx ;
x x;
x x2 = std::move(x); // 使用合成的移動建構函式
hasx hx;
hasx hx2 = std::move(hx); //使用合成的移動建構函式
但是在列舉的四種情況就是錯的,移動操作則會被定義為刪除的。
注意:定義了乙個移動建構函式或移動賦值運算子的類必須也定義自己的拷貝操作,否則,這些成員預設地被定義為刪除的。
如果乙個類既有移動建構函式,也有拷貝建構函式,編譯器則會使用普通的函式匹配規則來確定會使用哪個建構函式,賦值也是類似;
如果乙個類沒有移動建構函式,那麼函式匹配原則則會保證該型別的物件會被拷貝,即使試圖通過呼叫move來移動也是如此;
例子:
class foo ;
foo f1;
foo f2(f1); //拷貝建構函式
foo f3(std::move(f1)); //拷貝建構函式,因為未定義移動建構函式
注意:用拷貝操作代替移動操作是安全的,一般情況下,前者都會滿足後者的要求;
拷貝並交換賦值運算子和移動操作
同時實現移動建構函式和賦值運算子:
class person
// 賦值運算子既是移動賦值運算子,也是拷貝賦值運算子
person& operator=(person p)
private:
string name;
};
賦值運算子會交換兩個物件的指標以及成員,在swap之後,p的指標會指向this,而this則會指向p的記憶體,當p離開其作用域之後,其的成員也會被銷毀,自然兩者就會同時實現嘍~; 第十三章 第六小節 物件移動
最近在看c primer的時候,對於物件移動一直不太懂,所以在查詢各種資料,仔細研究 後,打算寫篇部落格記錄下來,果然還是不要得過且過,看見不懂的就查,弄懂為止最好了。很多時候都會發生物件拷貝,但是拷貝有個問題,對於有些僅僅做完拷貝就銷毀的情況,其實沒必要,更好的做法是進行移動元素 在新標準中,可以...
第十三章 13 2 1節練習
練習13.23 比較上一節練習中你編寫的拷貝控制成員和這一節中的 確定你理解了你的 和我們的 之間的差異 如果有的話 解答 這道題的解答建立在你對13.22題的實現上面,如果個人實現了,可以進行對比。練習13.24 如果本節中的hasptr版本未定義析構函式,將會發生什麼?如果未定義拷貝建構函式,將...
第十三章 13 6 1節練習
練習13.45 解釋右值引用和左值引用的區別。解答 左值引用就是常規引用。右值引用是在c 11之後新增到c 的新特性。引用 對於常規引用,我們不能將其繫結到要求轉換的表示式 字面常量或是返回右值的表示式。引用 右值引用有著完全相反的繫結特性 我們可以講乙個右值引用繫結到這類表示式上,但是不能講乙個右...