C++11新特性——移动语义,右值引用
移動語義
有一些類的資源是__不可共享__的,這種類型的對象可以被移動但不能被拷貝,如:IO 或 unique_ptr
庫容器、string 和 shared_ptr 支持拷貝和移動,IO 和 unique_ptr 則只能移動不能拷貝。。
右值引用
右值引用是必須綁定到右值的引用,右值引用使用 && 符號,相較于左值引用的& 。右值引用有一個特性就是其只能綁定到即將銷毀的對象上,因而,可以自由的移動右值引用對象中的資源。
左值表示對象的身份,而右值表示對象的值。不能將左值引用(lvalue reference)綁定到需要轉(zhuǎn)型的值、字面量或者返回右值的表達式上。右值引用則剛好相反:可以將右值引用綁定到以上的值,但不能直接將右值引用綁定到左值。如:
int i = 42; int &r = i; int &&rr = i; //錯誤:不能將右值引用綁定到左值上 int &r2 = i * 42; //錯誤:不能將左值引用綁定到右值上 const int &r3 = i * 42; //可以將 const 左值引用綁定到任何類型的值上(const/非 const 的左/右值) int &&rr2 = i * 42; //將右值引用綁定到右值上返回左值引用的函數(shù)和賦值、下標(biāo)操作、解引用和前綴自增/自減操作符都是返回左值的表達式,可將左值引用綁定到這些表達式的結(jié)果中。
返回非引用類型的函數(shù)與算術(shù)、關(guān)系、位操作和后綴自增/自減的操作符都是返回右值的表達式,可將右值引用和 const 左值引用綁定到這種表達式上。
變量是左值
一個變量就是一個表達式,其只有一個操作數(shù)而沒有操作符。變量表達式是左值。因而,不能將右值引用綁定到一個定義為右值引用的變量上。如:
int &&rr1 = 42; int &&rr2 = rr1; //錯誤:rr1 是左值,因而不能這樣定義一個變量就是一個左值;不能直接將右值引用綁定到一個變量上,即使這個變量被定義為右值引用類型也不可以。
但是如果臨時對象通過一個接受右值的函數(shù)傳遞給另一個函數(shù)時,就會變成左值,因為這個臨時對象在傳遞過程中,變成了命名對象。
move庫函數(shù)
template< class T > (C++11 起) typename std::remove_reference<T>::type&& move( T&& t ) noexcept; (C++14 前) template< class T > (C++14 起) constexpr typename std::remove_reference<T>::type&& move( T&& t ) noexcept;可以顯式將左值強轉(zhuǎn)為對應(yīng)的右值引用類型,也可以通過調(diào)用 move 庫函數(shù)來獲取綁定到左值的右值引用,其被定義在 utility 頭文件中。如:
int &&rr3 = std::move(rr1);調(diào)用 move 告知編譯器,以右值方式對象一個左值。特別需要了解的是調(diào)用 move 將承諾:不會再次使用 rr1 ,除非是賦值或者析構(gòu)。當(dāng)調(diào)用了 move 之后,不能對這個對象做任何值上的假設(shè)。可以析構(gòu)或賦值給移動后的對象,但在此之前不能使用其值。
使用 move 的代碼應(yīng)該使用 std::move ,而不是 move,這樣做可以避免潛在的名字沖突。
移動構(gòu)造函數(shù)和移動賦值
為了讓我們自己的類可以執(zhí)行移動操作,需要定義移動構(gòu)造函數(shù)和移動賦值操作符。這些成員類似于對應(yīng)的拷貝賦值操作,但是他們將從給定對象中偷取資源而不是復(fù)制。
除了移動資源,移動構(gòu)造函數(shù)需要保證移動后的對象的狀態(tài)是析構(gòu)無害的。特別是,一旦資源被移動后,原始對象就不再指向移動了的資源,這些所有權(quán)被轉(zhuǎn)移給了新創(chuàng)建的對象。如:
StrVec::StrVec(StrVec &&s) noexcept :elements(s.elements), first_free(s.first_free), cap(s.cap) {s.elements = s.first_free = s.cap = nullptr; }與拷貝構(gòu)造函數(shù)不同,移動構(gòu)造函數(shù)并不會分配新資源;其將攫取參數(shù)中的內(nèi)存,在此之后,構(gòu)造函數(shù)體將參數(shù)中的指針都設(shè)置為 nullptr,當(dāng)一個對象被移動后,這個對象依然存在。最后移動后的對象將被析構(gòu),意味著析構(gòu)函數(shù)將在此對象上運行。析構(gòu)函數(shù)將釋放其所擁有的資源,如果沒有將指針設(shè)置為 nullptr 的,就會將移動了的資源給釋放掉。
移動操作,庫容器和異常
移動操作通常不必自己分配資源,所以移動操作通常不拋出任何異常。當(dāng)我們寫移動操作時,由于其不會拋出異常,我們應(yīng)當(dāng)告知編譯器這個事實。除非編譯器知道這個事實,它將必須做額外的工作來滿足移動構(gòu)造操作將拋出異常。
通過在函數(shù)參數(shù)列表后加上 noexcept ,在構(gòu)造函數(shù)時則,noexcept 出現(xiàn)在參數(shù)列表后到冒號之間,來告知編譯器一個函數(shù)不會拋出異常。如:
class StrVec { public:StrVec(StrVec &&) noexcept; }; StrVec::StrVec(StrVec &&s) noexcept : { ... }必須同時在類體內(nèi)的聲明處和定義處同時指定 noexcept。
移動構(gòu)造函數(shù)和移動賦值操作符,如果都不允許拋出異常,那么就應(yīng)該被指定為 noexcept。
告知移動操作不拋出異常是由于兩個不相關(guān)的事實:第一,盡管移動操作通常不拋出異常,它們可以這樣做。第二,有些庫容器在元素是否會在構(gòu)建時拋出異常有不同的表現(xiàn),如:vector 只有在知道元素類型的移動構(gòu)造函數(shù)不會拋出異常才使用移動構(gòu)造函數(shù),否則將必須使用拷貝構(gòu)造函數(shù);
移動賦值操作符
StrVec& StrVec::operator=(StrVec &&rhs) noexcept {if (this == &rhs)return *this;free();elements = rhs.elements;first_free = rhs.first_free;cap = rhs.cap;rhs.elements = rhs.first_free = rhs.cap = nullptr;return *this; }移動賦值操作符不拋出異常應(yīng)當(dāng)用 noexcept 修飾,與拷貝賦值操作符一樣需要警惕自賦值的可能性。移動賦值操作符同時聚合了析構(gòu)函數(shù)和移動構(gòu)造函數(shù)的工作:其將釋放左操作數(shù)的內(nèi)存,并且占有右操作數(shù)的內(nèi)存,并將右操作數(shù)的指針設(shè)為 nullptr。
移動后的對象必須是可以析構(gòu)的
移動對象并不會析構(gòu)那個對象,有時在移動操作完成后,被移動的對象將被銷毀。因而,當(dāng)我們寫移動操作時,必須保證移動后的對象的狀態(tài)是可以析構(gòu)的。StrVec 通過將其指針設(shè)置為 nullptr 來滿足此要求。
除了讓對象處于可析構(gòu)狀態(tài),移動操作必須保證對象處于有效狀態(tài)。通常來說,有效狀態(tài)就是可以安全的賦予新值或者使用在不依賴當(dāng)前值的方式下。另一方面,移動操作對于遺留在移動后的對象中的值沒有什么特別要求,所以,程序不應(yīng)該依賴于移動后對象的值。
例如,從庫 string 和容器對象中移動資源后,移動后對象的狀態(tài)將保持有效。可以在移動后對象上調(diào)用 empty 或 size 函數(shù),然而,并不保證得到的結(jié)果是空的。可以期望一個移動后對象是空的,但是這并不保證。
以上 StrVec 的移動操作將移動后對象留在一個與默認初始化一樣的狀態(tài)。因而,這個 StrVec 的所有操作將與默認初始化的 StrVec 的操作完全一樣。其它類,有著更加復(fù)雜的內(nèi)部結(jié)構(gòu),也許會表現(xiàn)的不一致。
在移動后操作,移動后對象必須保證在一個有效狀態(tài),并且可以析構(gòu),但是用戶不能對其值做任何假設(shè)。
*合成移動操作
編譯器會為對象合成移動構(gòu)造函數(shù)和移動賦值操作符。然而,在什么情況下合成移動操作與合成拷貝操作是十分不同的。
與拷貝操作不同的,對于某些類來說,編譯器根本不合成任何移動操作。特別是,如果一個類定義自己的拷貝構(gòu)造函數(shù)、拷貝賦值操作符或析構(gòu)函數(shù),移動構(gòu)造函數(shù)和移動賦值操作符是不會合成的。作為結(jié)果,有些類是沒有移動構(gòu)造函數(shù)或移動賦值操作符。同樣,當(dāng)一個類沒有移動操作時,對應(yīng)的拷貝操作將通過函數(shù)匹配被用于替代移動操作。
編譯器只會在類沒有定義任何拷貝控制成員并且所有的非 static 數(shù)據(jù)成員都是可移動的情況下才會合成移動構(gòu)造函數(shù)和移動賦值操作符。編譯器可以移動內(nèi)置類型的成員,亦可以移動具有對應(yīng)移動操作的類類型成員。
移動操作不會隱式被定義為刪除的,而是根本不定義,當(dāng)沒有移動構(gòu)造函數(shù)時,重載將選擇拷貝構(gòu)造函數(shù)。當(dāng)用 =default 要求編譯器生成時,如果編譯器無法移動所有成員,將會生成一個刪除的移動操作。被刪除的函數(shù)不是說不能被用于函數(shù)重載,而是說當(dāng)其是重載解析時最合適的候選函數(shù)時,將是編譯錯誤。
- 與拷貝構(gòu)造函數(shù)不同,當(dāng)類有一個成員定義了自己的拷貝構(gòu)造函數(shù),但是沒有定義移動構(gòu)造函數(shù)時使用拷貝構(gòu)造函數(shù)。當(dāng)成員沒有定義自己的拷貝操作但是編譯器無法為其合成移動構(gòu)造函數(shù)時,其移動構(gòu)造函數(shù)被定義為被刪除的。對于移動賦值操作符是一樣的;
- 如果類有一個成員其移動構(gòu)造函數(shù)或移動賦值操作符是被刪除的或不可訪問的,其移動構(gòu)造函數(shù)或移動賦值操作符被定義為被刪除的;
- 與拷貝構(gòu)造函數(shù)一樣,如果其析構(gòu)函數(shù)是被刪除的或不可訪問的,移動構(gòu)造函數(shù)被定義為被刪除的;
- 與拷貝賦值操作符一樣,如果其有一個 const 或引用成員,移動賦值操作被定義為刪除的;
如果一個類定義自己的移動構(gòu)造函數(shù)或移動賦值操作符,那么合成的拷貝構(gòu)造函數(shù)和拷貝賦值操作符都將被定義為被刪除的。
右值移動,左值拷貝
當(dāng)一個類既有移動構(gòu)造函數(shù)又有拷貝構(gòu)造函數(shù),編譯器使用常規(guī)的函數(shù)匹配來決定使用哪個構(gòu)造函數(shù)。拷貝構(gòu)造函數(shù)通常使用 const StrVec 引用類型作為參數(shù),因而,可以匹配可以轉(zhuǎn)為 StrVec 類型的對象參數(shù)。而移動構(gòu)造函數(shù)則使用 StrVec && 作為參數(shù),因而,只能使用非 const 的右值。如果調(diào)用拷貝形式的,需要將參數(shù)轉(zhuǎn)為 const 的,而移動形式的卻是精確匹配,因而,右值將調(diào)用移動形式的。
右值在無法被移動時進行拷貝
如果一個類有拷貝構(gòu)造函數(shù),但是沒有定義移動構(gòu)造函數(shù),在這種情況下編譯不會合成移動構(gòu)造函數(shù),意味著類只有拷貝構(gòu)造函數(shù)而沒有移動構(gòu)造函數(shù)。如果一個類沒有移動構(gòu)造函數(shù),函數(shù)匹配保證即便是嘗試使用 move 來移動對象時,它們依然會被拷貝。
class Foo { public:Foo() = default;Foo(const Foo&); //拷貝構(gòu)造函數(shù) }; Foo x; Foo y(x); //拷貝構(gòu)造函數(shù);x 是左值 Foo z(std::move(x)); //拷貝構(gòu)造函數(shù);因為沒有移動構(gòu)造函數(shù)調(diào)用 move(x) 時返回 Foo&& ,Foo 的拷貝構(gòu)造函數(shù)是可行的,因為可以將 Foo&& 轉(zhuǎn)為 const Foo& ,因而,使用拷貝構(gòu)造函數(shù)來初始化 z 。
使用拷貝構(gòu)造函數(shù)來替換移動構(gòu)造函數(shù)通常是安全的,對于賦值操作符來說是一樣的。拷貝構(gòu)造符合移動構(gòu)造函數(shù)的先決條件:它將拷貝給定的對象,并且不會改變其狀態(tài),這樣原始對象將保持在有效狀態(tài)內(nèi)。
拷貝和交換賦值操作與移動
class HasPtr { public:HasPtr(HasPtr &&p) noexcept : ps(p.ps), i(p.i) {p.ps = 0;}HasPtr& operator=(HasPtr rhs){swap(*this, rhs);return *this;} };賦值操作符的參數(shù)是非引用類型的,所以參數(shù)是拷貝初始化的。根據(jù)參數(shù)的類型,拷貝初始化可能使用拷貝構(gòu)造函數(shù)也可能使用移動構(gòu)造函數(shù)。左值將被拷貝,右值將被移動。因而,這個移動操作符既是拷貝賦值操作符又是移動賦值操作符。如:
hp = hp2; hp = std::move(hp2);所有五個拷貝控制成員應(yīng)該被當(dāng)做一個整體:通常,如果一個類定義了其中任何一個操作,它通常需要定義所有成員。有些類必須定義拷貝構(gòu)造函數(shù),拷貝賦值操作符和析構(gòu)函數(shù)才能正確工作。這種類通常有一個資源是拷貝成員必須拷貝的,通常拷貝資源需要做很多額外的工作,定義移動構(gòu)造函數(shù)和移動賦值操作符可以避免在不需要拷貝的情況的額外工作。
移動迭代器
在新標(biāo)準中,定義了移動迭代器(move iterator)適配器。移動迭代器通過改變迭代器的解引用操作來適配給定的迭代器。通常,迭代器解引用返回元素的左值引用,與其它迭代器不同,解引用移動迭代器返回右值引用。調(diào)用函數(shù) make_move_iterator 將常規(guī)迭代器變成移動迭代器,移動迭代器的操作與原始迭代器操作基本一樣,因而可以將移動迭代器傳給 uninitialized_copy 函數(shù)。如:
uninitialized_copy(make_move_iterator(begin()), make_move_iterator(end()));值得一提的是標(biāo)準庫沒有說哪些算法可以使用移動迭代器,哪些不可以。因為移動對象會破壞原始對象,所以將移動迭代器傳給那些不會在移動后訪問其值的算法才合適。
慎用移動操作:由于移動后的對象處于中間狀態(tài),在對象上調(diào)用 std::move 是很危險的。當(dāng)調(diào)用 move 后,必須保證沒有別的用戶使用移動后對象。
謹慎克制的在類內(nèi)使用 move 可以提供重大的性能提升,在用戶代碼中使用 move 則更可能導(dǎo)致難以定位的 bug,相比較得到的性能提升是不值得的。
在類實現(xiàn)代碼外使用 std::move,必須是在確實需要移動操作,并且保證移動是安全的。
右值引用和成員函數(shù)
除了構(gòu)造函數(shù)和賦值操作符外提供拷貝和移動版本亦會受益。這種可以移動的成員函數(shù)中一個使用 const 左值引用,另一個使用非 const 右值引用。如:
void push_back(const X&); //拷貝:綁定到任何類型的 X void push_back(X&&); //移動:綁定到可修改的右值 X可以傳遞任何可以轉(zhuǎn)換為類型 X 的對象給拷貝版本,這個版本從參數(shù)中拷貝數(shù)據(jù)。只能將非 const 右值傳遞給移動版本。此版本比拷貝版本更好的匹配非 const 右值(精確匹配),因而,在函數(shù)匹配中將是更優(yōu)的,并且可以自由的從參數(shù)中移動資源。
通常上面這種重載方式不會使用 const X&& 和 X& 類型的參數(shù),原因在于移動數(shù)據(jù)要求對象是非 const 的,而拷貝數(shù)據(jù)則應(yīng)該是 const 的。
以拷貝或移動的方式對函數(shù)進行重載,常用的做法是一個版本使用 const T& 為參數(shù),另外一個版本使用 T&& 為參數(shù)。
右值與左值引用的成員函數(shù)
有些成員函數(shù)是只允許左值調(diào)用的,右值是不能調(diào)用的,如:在新標(biāo)準前可以給兩個字符串拼接的結(jié)果賦值:s1 + s2 = "wow!"; ,在新標(biāo)準中可以強制要求賦值操作符的左操作數(shù)是左值,通過在參數(shù)列表后放置引用修飾符(reference qualifier)可以指示 this 的左值/右值特性。如:
class Foo { public:Foo& operator=(const Foo&) &; }; Foo& Foo::operator=(const Foo& rhs) & { return *this; }引用修飾符可以是 & 或者 && 用于表示 this 指向左值或右值。與 const 修飾符一樣,引用修飾符必須出現(xiàn)在非 static 成員函數(shù)的聲明和定義處。被 & 修飾的函數(shù)只能被左值調(diào)用,被 && 修飾的函數(shù)只能被右值調(diào)用。
一個函數(shù)既可以有 const 也可以有引用修飾符,在這種情況下,引用修飾符在 const 修復(fù)符的后面。如:
class Foo { public:Foo someMem() const &; };重載帶引用修飾符的成員函數(shù)
可以通過函數(shù)的引用修飾符進行重載,這與常規(guī)的函數(shù)重載是一樣的,&& 可以在可修改的右值上調(diào)用,const & 可以在任何類型的對象上調(diào)用。如:
class Foo { public:Foo sorted() &&; //可以在可修改的右值上調(diào)用Foo sorted() const &; //可以在任何類型的 Foo 上調(diào)用 };當(dāng)定義具有相同名字和相同參數(shù)列表的成員函數(shù)時,必須同時提供引用修飾符或者都不提供引用修飾符,如果只在其中一些提供,而另外一些不提供就是編譯錯誤。如:
class Foo { public:Foo sorted() &&;Foo sorted() const; //錯誤:必須提供引用修飾符//全不提供引用修飾符是合法的using Comp = bool(const int&, const int&);Foo sorted(Comp*);Foo sorted(Comp*) const; };精確傳遞 (Perfect Forwarding)
本文采用精確傳遞表達這個意思。Perfect Forwarding也被翻譯成完美轉(zhuǎn)發(fā),精準轉(zhuǎn)發(fā)等,說的都是一個意思。
精確傳遞適用于這樣的場景:需要將一組參數(shù)原封不動的傳遞給另一個函數(shù)。
“原封不動”不僅僅是參數(shù)的值不變,在 C++ 中,除了參數(shù)值之外,還有一下兩組屬性:
左值/右值和 const/non-const。 精確傳遞就是在參數(shù)傳遞過程中,所有這些屬性和參數(shù)值都不能改變。在泛型函數(shù)中,這樣的需求非常普遍。
下面舉例說明。函數(shù) forward_value 是一個泛型函數(shù),它將一個參數(shù)傳遞給另一個函數(shù) process_value。
forward_value 的定義為:
template <typename T> void forward_value(const T& val) {process_value(val); } template <typename T> void forward_value(T& val) {process_value(val); }函數(shù) forward_value 為每一個參數(shù)必須重載兩種類型,T& 和 const T&,否則,下面四種不同類型參數(shù)的調(diào)用中就不能同時滿足 :
int a = 0;const int &b = 1;forward_value(a); // int&forward_value(b); // const int& forward_value(2); // int&對于一個參數(shù)就要重載兩次,也就是函數(shù)重載的次數(shù)和參數(shù)的個數(shù)是一個正比的關(guān)系。這個函數(shù)的定義次數(shù)對于程序員來說,是非常低效的。我們看看右值引用如何幫助我們解決這個問題 :
template <typename T> void forward_value(T&& val) {process_value(val); }只需要定義一次,接受一個右值引用的參數(shù),就能夠?qū)⑺械膮?shù)類型原封不動的傳遞給目標(biāo)函數(shù)。四種不用類型參數(shù)的調(diào)用都能滿足,參數(shù)的左右值屬性和 const/non-cosnt屬性完全傳遞給目標(biāo)函數(shù) process_value。這個解決方案不是簡潔優(yōu)雅嗎?
int a = 0; const int &b = 1; forward_value(a); // int& forward_value(b); // const int& forward_value(2); // int&&C++11 中定義的 T&& 的推導(dǎo)規(guī)則為:
右值實參為右值引用,左值實參仍然為左值引用。
一句話,就是參數(shù)的屬性不變。這樣也就完美的實現(xiàn)了參數(shù)的完整傳遞。
右值引用,表面上看只是增加了一個引用符號,但它對 C++ 軟件設(shè)計和類庫的設(shè)計有非常大的影響。它既能簡化代碼,又能提高程序運行效率。每一個 C++ 軟件設(shè)計師和程序員都應(yīng)該理解并能夠應(yīng)用它。我們在設(shè)計類的時候如果有動態(tài)申請的資源,也應(yīng)該設(shè)計轉(zhuǎn)移構(gòu)造函數(shù)和轉(zhuǎn)移拷貝函數(shù)。在設(shè)計類庫時,還應(yīng)該考慮 std::move 的使用場景并積極使用它。
關(guān)鍵術(shù)語
-
拷貝-交換(copy and swap):一種書寫賦值操作符的技術(shù),先將右操作數(shù)拷貝到參數(shù)中,然后調(diào)用 swap 將其與左操作數(shù)進行交換;
-
拷貝賦值操作符(copy-assignment operator):拷貝賦值操作符與本類的 const 引用對象作為參數(shù),返回對象的引用。如果類不定義拷貝賦值操作符,編譯器將合成一個;
-
拷貝構(gòu)造函數(shù)(copy constructor):將新對象初始化為本類的另一個對象的副本的構(gòu)造函數(shù)。拷貝構(gòu)造函數(shù)將在以非引用方式傳遞參數(shù)或從函數(shù)中返回時默認調(diào)用。如果類不定義的話,編譯器將合成一個;
-
拷貝控制(copy control):用于控制對象被拷貝、移動、賦值和銷毀時應(yīng)當(dāng)做什么的成員函數(shù)。如果類不定這些函數(shù),編譯器將在合適的時候合成它們;
-
拷貝初始化(copy initialization):使用 = 形式的初始化,或者當(dāng)傳遞參數(shù)、按值形式返回值,或者初始化數(shù)組或聚合類時,將進行拷貝初始化。拷貝初始化將根據(jù)初始值是左值還是右值,使用拷貝構(gòu)造函數(shù)或者移動構(gòu)造函數(shù);
-
被刪除的函數(shù)(deleted function):不被使用的函數(shù),通過 =delete 來刪除函數(shù)。使用被刪除的函數(shù)是告知編譯器在進行函數(shù)匹配時,如果匹配到被刪除的函數(shù)就報編譯器錯誤;
-
析構(gòu)函數(shù)(destructor):當(dāng)對象離開作用域時調(diào)用的特殊成員函數(shù)來清理對象。編譯器自動銷毀每個數(shù)據(jù)成員,類成員通過調(diào)用其析構(gòu)函數(shù)進行銷毀,內(nèi)置類型或符合類型將不做任何析構(gòu)操作,特別是指向動態(tài)對象的指針不會被自動 delete;
-
逐個成員拷貝/賦值(memberwise copy/assign):合成的拷貝/移動構(gòu)造函數(shù)和拷貝/移動賦值操作符的運作方式。依次對所有的數(shù)據(jù)成員,拷貝/移動構(gòu)造函數(shù)通過從參數(shù)中拷貝/移動對應(yīng)的成員進行初始化;拷貝/移動賦值操作符則依次對右操作數(shù)的各個成員進行拷貝/移動賦值;內(nèi)置類型的成員是直接進行初始化或賦值的。類類型成員則調(diào)用對應(yīng)的拷貝/移動構(gòu)造函數(shù)或拷貝/移動賦值操作符;
-
move 函數(shù)(move function):用于將左值綁定到右值引用的庫函數(shù)。調(diào)用 move 將隱式保證不會使用移動后的對象值,唯一的操作是析構(gòu)或者賦予新值;
-
移動賦值操作符(move-assignment operator):參數(shù)是右值引用的賦值操作符版本。通常移動賦值操作符將其右操作數(shù)的數(shù)據(jù)移動到左操作數(shù)。在賦值后,必須保證可以安全的析構(gòu)掉右操作數(shù);
-
移動構(gòu)造函數(shù)(move constructor):以右值引用為參數(shù)的構(gòu)造函數(shù)。移動構(gòu)造函數(shù)將參數(shù)中的數(shù)據(jù)移動到新創(chuàng)建的對象中。在移動后,必須保證可以安全地析構(gòu)掉右操作數(shù);
-
移動迭代器(move iterator):迭代器適配器,包裝一個迭代器,當(dāng)其解引用時返回右值引用;
-
右值引用(rvalue reference):對即將被銷毀的對象的引用;
總結(jié)
以上是生活随笔為你收集整理的C++11新特性——移动语义,右值引用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HTML5如何添加图片遮罩,带有HTML
- 下一篇: html3d上下翻转4面效果,花式实现图