移動建構函式與移動賦值運算子

2021-07-23 18:09:37 字數 3464 閱讀 8497

定義:新標準的乙個主要的特性是可以移動而不拷貝物件的能力,乙個典型的例子是在分配新記憶體的過程中,將元素從就舊記憶體拷貝到新記憶體中是不必要的(先拷貝元素,在釋放舊記憶體),再者,如果乙個類中含有io類和unique_ptr類那麼只能使用移動建構函式

右值引用&&

定義:右值引用只能繫結到乙個即將銷毀的物件上,

右值引用只能繫結到乙個即將銷毀的物件(臨時物件)

1,所引用的物件即將被銷毀

2,該物件沒有其他使用者

由以上兩點可知,使用右值引用的**可以自由接管所引用物件的記憶體管理權。

左值與右值的區分

一般而言左值是乙個物件的值,右值是乙個物件的名字。

右值型別繫結到右值引用

要求轉換的表示式       例如:  i*42;

字面常量 (字)

返回非引用型別的函式 (非)

算術運算子 (算)

關係運算子 (關)

位運算子 (位)

後置遞增,遞減運算子 (後)

左值型別繫結到左值引用

變數             (變)

返回引用的函式 (引)

賦值運算子 (賦)

下標運算子 (下)

解引用運算子 (解)

前置遞增,遞減運算子 (前)

口決:字非算位關後右,變引下賦解前左

int i=42; //

42字面值為右,i 變數為左值

int &lr=i; //左值引用繫結到乙個左值上

int &&rr=i; //錯誤:不能將乙個右值引用繫結乙個左值上

int &lr=i*8; //錯誤:不能將乙個左值引用繫結到乙個右值上

/* i*8 是乙個表示式

const int &lr=i*4;//正確:可以將const左值引用繫結到右值上

int &&rr=i*8;// 正確:將右值引用繫結到右值上

變數是左值,我們把右值引用直接繫結到乙個變數上,即使這個變數是右值引用型別也不行。

int& rr1=43;   //rr1是右值引用

int& rr2=rr1; //錯誤:rr1是左值(rr1是乙個變數,左值)

/* 字非算位關後右,變引下賦解前左 */

但是我們能夠顯示地將乙個左值轉換成右值引用型別,也可以通過呼叫乙個std::move( variable)來獲得繫結到左值上的右值引用。以下程式表明,rr1是乙個左值但是我們希望像右值一樣處理它:除了對rr1進行賦值與銷毀外,我們不能進行其他操作

int &&rr3=std::move(rr1);//rr3是右值引用,但是是左值(變數)

/* 字非算位關後右,變引下賦解前左 */

移動建構函式

移動建構函式與移動賦值運算子,這兩個成員函式類似拷貝操作,但是他們從給定物件中「竊取」資源而不是拷貝資源。

移後新物件=移動建構函式(給定物件);    //給定物件——>移後源物件
移動後源物件必須不再指向被移動的資源,這些資源的所有權都歸新建立的物件所有,我們可以對乙個移後源物件進行賦值和銷毀但是不能使用它的值

解釋為什麼不能使用移後源物件的值

因為移動後移後源物件不再指向移動的資源,因此使用移動源物件傳遞給程式的值不再是移動前的值,在程式執行中就會出錯

1,移動建構函式的第乙個引數是乙個右值引用,其他引數具有預設值

2,必須保證對移後源物件執行銷毀操作無害

strvec::strvec(strvec&&s)noexcept:

elements(s.elements),first_free(s.first_free),cap(s.cap)//保證銷毀移後源物件是安全的

移動建構函式與類指標拷貝建構函式的區別是,移動後移後源物件不再管理移動的資源,把移動資源的管理權交給了移後的新物件。也就是說移動建構函式不分配新的記憶體,它接管給定物件的記憶體,在接管後把給定物件中的指標都置為nullptr。

類指標拷貝使用shared_ptr拷貝後新物件與源物件共享資源的管理(可以對資源進行賦值,使用和銷毀)

移動賦值運算子

移動賦值運算子比移動建構函式多了一項功能就是在接管記憶體之前先釋放被賦值物件的記憶體

strvec& strvec::operator=(strvec&&s)noexcept

return *this;

}

補充物件有效的概念:

物件有效是指可對其進行賦值,銷毀和使用其值;

移後源物件仍讓是有效的但是我們不應該在使用移後源物件的值

合成的移動操作

如果類定義了拷貝建構函式,拷貝賦值運算子,或是析構函式編譯器將不會合成移動建構函式與移動賦值運算子,在未定義移動操作時,使用移動操作將會通過函式匹配呼叫拷貝操作來代替移動操作

只有當類沒有定義拷貝控制成員,且類的每乙個非static資料成員都可以移動時,編譯器才會合成移動操作,如果定義了移動操作也應該定義拷貝操作否則拷貝操作被預設為刪除的

即:定義了拷貝操作與移動操作中的乙個,編譯器不會合成另乙個

如果有類成員是const或是引用,則類的移動賦值運算子被定已成刪除的

刪除的移動操作

不能顯示的定義移動操作是刪除的,但在以下情況中可以隱式定義刪除的移動操作

移動右值拷貝左值

strvec v1,v2;

v1=v2;//v2是乙個左值(變:變數),呼叫拷貝建構函式

strvec getvec(istream &); //返回右值(非:返回非引用型別)

v2=getvec(v1);//呼叫移動建構函式

/* 字非算位關後右,變引下賦解前左 */

移動迭代器介面卡

定義:一般乙個迭代器的解引用運算子返回乙個指向元素的左值,但是移動迭代器的解引用返回乙個指向元素的右值引用

make_move_iterator();

此函式接受乙個迭代器作為引數,返回乙個移動迭代器

auto move_iter=make_move_iterator(begin());
移動迭代器支援普通迭代器的功能

參考:c++primer 第五版 :拷貝控制

物件移動,移動建構函式與移動賦值運算子

一 物件移動的概念 把乙個物件的所有權轉交給另乙個物件。完成必要的記憶體移動,斬斷原物件和記憶體的關係。二 移動建構函式 呼叫移動建構函式的情形 函式返回乙個物件時。include include using namespace std classa a a const a temp p new i...

移動構造和移動賦值運算子

只是自動幫你呼叫析構。得自己確保寫對這個函式。比如把指標指向清0,讓移後源物件達到乙個安全的可析構狀態。strvec strvec strvec noexcept elements s.elements first free s.first free cap s.cap 容器要保證發生異常時物件沒有...

C 移動建構函式和移動賦值運算子

c 11引入了物件移動而非拷貝的概念,有時候物件發生拷貝後就被銷毀了,這種情況下移動而非拷貝物件會大幅度提公升效能。移動建構函式類似於拷貝建構函式,不同的是移動建構函式的第乙個引數是乙個右值引用,移動建構函式僅僅移動資料成員,不會分配新的記憶體,所以比拷貝建構函式效能更好。移動賦值運算子與拷貝賦值運...