1. 程式人生 > >C++複製建構函式&移動建構函式,複製賦值運算子&移動賦值運算子

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、移動賦值運算子