C 11 移動建構函式

2021-09-05 08:44:54 字數 3678 閱讀 8146

移動建構函式是什麼?先舉個例子,你有一本書,你不想看,但我很想看,那麼我有哪些方法可以讓我能看這本書?有兩種做法,一種是你直接把書交給我,另一種是我去買一些稿紙來,然後照著你這本書一字一句抄到稿紙上。

顯然,第二種方法很浪費時間,但這正是有些深拷貝建構函式的做法,而移動建構函式便能像第一種做法一樣省時,第一種做法在 c++ 中叫做完美**。

何為左值?能用取址符號&取出位址的皆為左值,剩下的都是右值。

而且,匿名變數一律屬於右值。

int i =1;

// i 是左值,1 是右值

int getzero

//j 是左值,getzero() 是右值,因為返回值存在於暫存器中

int j =

getzero()

;//s 是左值,string("no name") 是匿名變數,是右值

string s =

string

("no name"

);

用 g++ 編譯器編譯下列**時記得加上引數-fno-elide-constructors

#include

#include

using

namespace std;

class

integer

//引數為左值引用的深拷貝建構函式,轉移堆記憶體資源所有權,改變 source.ptr_ 的值

integer

(integer& source)

:ptr_

(source.ptr_)

integer

(int value)

:ptr_

(new

int(value))~

integer()

intgetvalue

(void

)private

: string name_;

int* ptr_;};

intmain

(int argc,

char

const

* argv)

執行結果如下。

call integer(int value)

call integer(const integer& source)

call ~integer()

100-----------------

call integer(int value)

call integer(integer& source)

10000

-----------------

call ~integer()

call ~integer()

call ~integer()

在程式中,引數為常量左值引用的深拷貝建構函式的做法相當於引言中的第二種做法,「重買稿紙」相當於再申請一次堆記憶體資源,「重新抄寫」相當於把匿名物件integer(100)的資源拷貝到物件a這邊;引數為左值引用的深拷貝建構函式的做法則相當於引言中的第一種做法,語句ptr_(source.ptr_)source.ptr_ = nullptr;的作用相當於「我直接把書拿給你」。

由執行結果可以看出,當同時存在引數型別為常量左值引用和左值引用的深拷貝建構函式時,匿名物件integer(100)只能選擇前者,非匿名物件temp可以選擇後者,這是因為常量左值引用可以接受左值、右值、常量左值、常量右值,而左值引用只能接受左值。因此,對於匿名變數,引數為任何型別左值引用的深拷貝建構函式都無法實現完美**。還有一種辦法——右值引用。

右值引用也是引用的一種,引數型別為右值引用的函式只能接受右值引數,但不包括模板函式,引數型別為右值引用的模板函式不在本文討論的範圍內。

移動建構函式是引數型別為右值引用的拷貝建構函式。

在「三」示例程式interger類的定義中新增乙個移動建構函式,其餘保持原樣。

//引數為左值引用的深拷貝建構函式,轉移堆記憶體資源所有權,改變 source.ptr_ 的值

integer

(integer& source)

:ptr_

(source.ptr_)

//移動建構函式,與引數為左值引用的深拷貝建構函式基本一樣

integer

(integer&& source)

:ptr_

(source.ptr_)

integer

(int value)

:ptr_

(new

int(value)

)

執行結果如下。

call integer(int value)

call integer(integer&& source)

call ~integer()

100-----------------

call integer(int value)

call integer(integer& source)

10000

-----------------

call ~integer()

call ~integer()

call ~integer()

只有第二行跟先前不同,匿名物件integer(100)也能通過移動建構函式實現完美**。

大家可能會有疑問,上文提及到常量左值引用也可以接受右值,而右值引用也可以接受右值,那乙個右值是否有可能會套入乙個引數型別為常量左值引用的函式呢?答案是不會,乙個右值要套入函式時,會優先選擇套入引數型別為右值引用的函式

可是仔細想想還是有點不滿意,如果要讓左值和右值的深拷貝都能實現完美**,就需要寫兩個內容基本一樣的拷貝建構函式,乙個引數為(非常量)左值引用,乙個引數為右值,那能不能只用乙個函式就能實現左值、右值兩者的深拷貝完美**呢?答案就是強制型別轉換,將左值強制強制轉換為右值,再套入引數型別為右值引用的深拷貝建構函式。

std::move()能把左值強制轉換為右值。

我們把語句integer b(temp);改為integer b(std::move(temp));後,執行結果如下。

call integer(int value)

call integer(integer&& source)

call ~integer()

100-----------------

call integer(int value)

call integer(integer&& source)

10000

-----------------

call ~integer()

call ~integer()

call ~integer()

從「10000」的上一行可以看出,std::move()確實把左值temp轉換為右值。

《從4行**看右值引用》 使用者「qicosmos(江南)」 著

c 11 移動構造 移動賦值 拷貝構造

最近對準備深入學習一下c 11所有的新特性,今天研究了一下c 11的std move和std forward,在研究這個的時候,需要對c 0xx的拷貝構造,拷貝賦值有一些了解.這個不知道的自己去了解,這裡記錄一下c 11新加的移動版本 移動構造 移動賦值和拷貝構造 拷貝賦值的比較,文章引用 現代c ...

C 11新特性 移動建構函式和移動賦值

移動建構函式就是從拷貝建構函式演化而來的。拷貝建構函式又分為淺拷貝和深拷貝 因此就產生了移動建構函式,將原來物件的東西移動到新的物件上 移動後當物件銷毀時不能發生錯誤 移動後原物件不再指向被移動的資源,這些資源的所有權已經歸屬新建立的物件 a a x a a x 上面兩種就是拷貝建構函式和移動建構函...

C 11 委派建構函式

一 委派建構函式 深入理解c 11 委派構造 就是指委派函式將構造的任務派給了目標建構函式來完成這樣一種類構造的方式。c 11中的委派建構函式是在建構函式的初始化列表位置進行構造的 委派的 基準版本 的建構函式稱為目標建構函式,呼叫 基準版本 的建構函式稱為委派建構函式 舉例 namespace d...