C++複製建構函式&移動建構函式,複製賦值運算子&移動賦值運算子
一、呼叫時機
1、複製建構函式呼叫的時機
·物件在建立時使用其他的物件初始化
Person p(q); //此時複製建構函式被用來建立例項p
Person p = q; //此時複製建構函式被用來在定義例項p時初始化p
return_p() //當函式返回該型別的物件時呼叫
·物件作為函式的引數進行值傳遞時
f(p); //此時p作為函式的引數進行值傳遞,p入棧時會呼叫複製建構函式建立一個區域性物件,與函式內的區域性變數具有相同的作用域
p = q; //此時沒有複製建構函式的呼叫!賦值並不會呼叫複製建構函式,賦值只是賦值運算子(過載)在起作用
簡單來記的話就是,如果物件在宣告的同時將另一個已存在的物件賦給它,就會呼叫複製建構函式;如果物件已經存在,然後將另一個已存在的物件賦給它,呼叫的就是賦值運算子(過載)
注意:預設的複製建構函式和賦值運算子進行的都是"shallow copy",淺複製——在C++中,在用一個物件初始化另一個物件時,只複製了成員,並沒有複製資源,使兩個物件同時指向了同一資源的複製方式稱為淺複製。淺複製存在資源矛盾,導致兩次呼叫解構函式時後面呼叫者出錯。
因此如果物件中含有動態分配的記憶體,就需要我們自己重寫複製建構函式或者過載賦值運算子來實現"deep copy",確保資料的完整性和安全性。
2、移動建構函式呼叫的時機
首先有移動建構函式並且可以訪問。
移動建構函式接收的是“右值引用”的引數。
移動建構函式何時觸發? 那就是臨時物件(右值)。用到臨時物件的時候就會執行移動語義。
T &&a = return_a(); 如果臨時物件即將消亡,並且它裡面的資源是需要被其他物件再引用用的,這個時候我們就可以觸發移動構造。
T b = return_b(); 複製構造
此時a是右值引用,他比b少了一次物件構造和物件析構的過程。a直接綁定了return_a()返回的臨時變數。
而b只是由臨時變數值(值拷貝)構造而成的。
應該可以看清楚了吧。右值引用就是讓返回的右值(臨時物件)重獲新生,延長生命週期。臨時物件析構了,但是右值引用存活。
不過要注意的是,右值引用不能繫結左值:
int a;
int &&c = a; 這樣是不行的。
3、複製賦值運算子
4、移動賦值運算子