国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
詳解C++右值引用

C++0x標(biāo)準(zhǔn)出來很長(zhǎng)時(shí)間了,引入了很多牛逼的特性[1]。其中一個(gè)便是右值引用,Thomas Becker的文章[2]很全面的介紹了這個(gè)特性,讀后有如醍醐灌頂,翻譯在此以便深入理解。

概述

右值引用是由C++0x標(biāo)準(zhǔn)引入c++的一個(gè)令人難以捉摸的特性。我曾偶爾聽到過有c++領(lǐng)域的大牛這么說:

每次我想抓住右值引用的時(shí)候,它總能從我手里跑掉。想把右值引用裝進(jìn)腦袋實(shí)在太難了。我不得不教別人右值引用,這太可怕了。

右值引用惡心的地方在于,當(dāng)你看到它的時(shí)候根本不知道它的存在有什么意義,它是用來解決什么問題的。所以我不會(huì)馬上介紹什么是右值引用。更好的方式是從它將解決的問題入手,然后講述右值引用是如何解決這些問題的。這樣,右值引用的定義才會(huì)看起來合理和自然。

右值引用至少解決了這兩個(gè)問題:

  1. 實(shí)現(xiàn)move語義
  2. 完美轉(zhuǎn)發(fā)(Perfect forwarding)

如果你不懂這兩個(gè)問題,別擔(dān)心,后面會(huì)詳細(xì)地介紹。我們會(huì)從move語義開始,但在開始之前要首先讓你回憶起c++的左值和右值是什么。關(guān)于左值和右值我很難給出一個(gè)嚴(yán)密的定義,不過下面的解釋已經(jīng)足以讓你明白什么是左值和右值。

在c語言發(fā)展的較早時(shí)期,左值和右值的定義是這樣的:左值是一個(gè)可以出現(xiàn)在賦值運(yùn)算符的左邊或者右邊的表達(dá)式e,而右值則是只能出現(xiàn)在右邊的表達(dá)式。例如:

int a = 42;                                                int b = 43;                                                // a與b都是左值                              a = b; // ok                                                b = a; // ok                                                a = a * b; // ok                                            // a * b是右值:                                      int c = a * b; // ok, 右值在等號(hào)右邊a * b = 42; // 錯(cuò)誤,右值在等號(hào)左邊

在c++中,我們?nèi)匀豢梢杂眠@個(gè)直觀的辦法來區(qū)分左值和右值。不過,c++中的用戶自定義類型引入了關(guān)于可變性和可賦值性的微妙變化,這會(huì)讓這個(gè)方法變的不那么地正確。我們沒有必要繼續(xù)深究下去,這里還有另外一種定義可以讓你很好的處理關(guān)于右值的問題:左值是一個(gè)指向某內(nèi)存空間的表達(dá)式,并且我們可以用&操作符獲得該內(nèi)存空間的地址。右值就是非左值的表達(dá)式。例如:

// 左值:                                                        //                                                                int i = 42;                                                        i = 43; // ok, i是左值int* p = &i; // ok, i是左值int& foo();                                                        foo() = 42; // ok, foo()是左值int* p1 = &foo(); // ok, foo()是左值// 右值:                                                        //                                                                int foobar();                                                      int j = 0;                                                        j = foobar(); // ok, foobar()是右值int* p2 = &foobar(); // 錯(cuò)誤,不能取右值的地址j = 42; // ok, 42是右值

如果你對(duì)左值和右值的嚴(yán)密的定義有興趣的話,可以看下Mikael Kilpel?inen的文章[3]。

move語義

假設(shè)class X包含一個(gè)指向某資源的指針或句柄m_pResource。這里的資源指的是任何需要耗費(fèi)一定的時(shí)間去構(gòu)造、復(fù)制和銷毀的東西,比如說以動(dòng)態(tài)數(shù)組的形式管理一系列的元素的std::vector。邏輯上而言X的賦值操作符應(yīng)該像下面這樣:

X& X::operator=(X const & rhs){  // [...]  // 銷毀m_pResource指向的資源  // 復(fù)制rhs.m_pResource所指的資源,并使m_pResource指向它  // [...]}

同樣X的拷貝構(gòu)造函數(shù)也是這樣。假設(shè)我們這樣來用X:

X foo(); // foo是一個(gè)返回值為X的函數(shù)X x;x = foo();

最后一行有如下的操作:

  1. 銷毀x所持有的資源
  2. 復(fù)制foo返回的臨時(shí)對(duì)象所擁有的資源
  3. 銷毀臨時(shí)對(duì)象,釋放其資源

上面的過程是可行的,但是更有效率的辦法是直接交換x和臨時(shí)對(duì)象中的資源指針,然后讓臨時(shí)對(duì)象的析構(gòu)函數(shù)去銷毀x原來擁有的資源。換句話說,當(dāng)賦值操作符的右邊是右值的時(shí)候,我們希望賦值操作符被定義成下面這樣:

// [...]// swap m_pResource and rhs.m_pResource// [...]

這就是所謂的move語義。在之前的c++中,這樣的行為是很難實(shí)現(xiàn)的。雖然我也聽到有的人說他們可以用模版元編程來實(shí)現(xiàn),但是我還從來沒有遇到過能給我解釋清楚如何具體實(shí)現(xiàn)的人。所以這一定是相當(dāng)復(fù)雜的。C++0x通過重載的辦法來實(shí)現(xiàn):

X& X::operator=(<mystery type> rhs){  // [...]  // swap this->m_pResource and rhs.m_pResource  // [...]  }

既然我們是要重載賦值運(yùn)算符,那么肯定是引用類型。另外我們希望具有這樣的行為:現(xiàn)在有兩種重載,一種參數(shù)是普通的引用,另一種參數(shù)是,那么當(dāng)參數(shù)是個(gè)右值時(shí)就會(huì)選擇,當(dāng)參數(shù)是左值是還是選擇普通的引用類型。

把上面的換成右值引用,我們終于看到了右值引用的定義。

右值引用

如果X是一種類型,那么X&&就叫做X的右值引用。為了更好的區(qū)分兩,普通引用現(xiàn)在被稱為左值引用。

右值引用和左值引用的行為差不多,但是有幾點(diǎn)不同,最重要的就是函數(shù)重載時(shí)左值使用左值引用的版本,右值使用右值引用的版本:

void foo(X& x); // 左值引用重載void foo(X&& x); // 右值引用重載X x;X foobar();foo(x); // 參數(shù)是左值,調(diào)用foo(X&)foo(foobar()); // 參數(shù)是右值,調(diào)用foo(X&&)

重點(diǎn)在于:

右值引用允許函數(shù)在編譯期根據(jù)參數(shù)是左值還是右值來建立分支。

理論上確實(shí)可以用這種方式重載任何函數(shù),但是絕大多數(shù)情況下這樣的重載只出現(xiàn)在拷貝構(gòu)造函數(shù)和賦值運(yùn)算符中,以用來實(shí)現(xiàn)move語義:

X& X::operator=(X const & rhs); // classical implementationX& X::operator=(X&& rhs){  // Move semantics: exchange content between this and rhs  return *this;}

實(shí)現(xiàn)針對(duì)右值引用重載的拷貝構(gòu)造函數(shù)與上面類似。

如果你實(shí)現(xiàn)了void foo(X&);,但是沒有實(shí)現(xiàn)void foo(X&&);,那么和以前一樣foo的參數(shù)只能是左值。如果實(shí)現(xiàn)了void foo(X const &);,但是沒有實(shí)現(xiàn)void foo(X&&);,仍和以前一樣,foo的參數(shù)既可以是左值也可以是右值。唯一能夠區(qū)分左值和右值的辦法就是實(shí)現(xiàn)void foo(X&&);。最后,如果只實(shí)現(xiàn)了實(shí)現(xiàn)void foo(X&&);,但卻沒有實(shí)現(xiàn)void foo(X&);void foo(X const &);,那么foo的參數(shù)將只能是右值。

強(qiáng)制move語義

c++的第一版修正案里有這樣一句話:“C++標(biāo)準(zhǔn)委員會(huì)不應(yīng)該制定一條阻止程序員拿起槍朝自己的腳丫子開火的規(guī)則?!眹?yán)肅點(diǎn)說就是c++應(yīng)該給程序員更多控制的權(quán)利,而不是擅自糾正他們的疏忽。于是,按照這種思想,C++0x中既可以在右值上使用move語義,也可以在左值上使用,標(biāo)準(zhǔn)程序庫中的函數(shù)swap就是一個(gè)很好的例子。這里假設(shè)X就是前面我們已經(jīng)重載右值引用以實(shí)現(xiàn)move語義的那個(gè)類。

template<class T>void swap(T& a, T& b){  T tmp(a);  a = b;  b = tmp;}X a, b;swap(a, b);

上面的代碼中沒有右值,所以沒有使用move語義。但move語義用在這里最合適不過了:當(dāng)一個(gè)變量(a)作為拷貝構(gòu)造函數(shù)或者賦值的來源時(shí),這個(gè)變量要么就是以后都不會(huì)再使用,要么就是作為賦值操作的目標(biāo)(a = b)。

C++11中的標(biāo)準(zhǔn)庫函數(shù)std::move可以解決我們的問題。這個(gè)函數(shù)只會(huì)做一件事:把它的參數(shù)轉(zhuǎn)換為一個(gè)右值并且返回。C++11中的swap函數(shù)是這樣的:

template<class T>void swap(T& a, T& b){  T tmp(std::move(a));  a = std::move(b);  b = std::move(tmp);}X a, b;swap(a, b);

現(xiàn)在的swap使用了move語義。值得注意的是對(duì)那些沒有實(shí)現(xiàn)move語義的類型來說(沒有針對(duì)右值引用重載拷貝構(gòu)造函數(shù)和賦值操作符),新的swap仍然和舊的一樣。

std::move是個(gè)很簡(jiǎn)單的函數(shù),不過現(xiàn)在我還不能將它的實(shí)現(xiàn)展現(xiàn)給你,后面再詳細(xì)說明。

像上面的swap函數(shù)一樣,盡可能的使用std::move會(huì)給我們帶來以下好處:

  • 對(duì)那些實(shí)現(xiàn)了move語義的類型來說,許多標(biāo)準(zhǔn)庫算法和操作會(huì)得到很大的性能上的提升。例如就地排序:就地排序算法基本上只是在交換容器內(nèi)的對(duì)象,借助move語義的實(shí)現(xiàn),交換操作會(huì)快很多。
  • stl通常對(duì)某種類型的可復(fù)制性有一定的要求,比如要放入容器的類型。其實(shí)仔細(xì)研究下,大多數(shù)情況下只要有可移動(dòng)性就足夠了。所以我們可以在一些之前不可復(fù)制的類型不被允許的情況下,用一些不可復(fù)制但是可以移動(dòng)的類型(unique_ptr)。這樣的類型是可以作為容器元素的。

右值引用是右值嗎?

假設(shè)有以下代碼:

void foo(X&& x){  X anotherX = x;  // ...}

現(xiàn)在考慮一個(gè)有趣的問題:在foo函數(shù)內(nèi),哪個(gè)版本的X拷貝構(gòu)造函數(shù)會(huì)被調(diào)用呢?這里的x是右值引用類型。把x也當(dāng)作右值來處理看起來貌似是正確的,也就是調(diào)用這個(gè)拷貝構(gòu)造函數(shù):

X(X&& rhs);

有些人可能會(huì)認(rèn)為一個(gè)右值引用本身就是右值。但右值引用的設(shè)計(jì)者們采用了一個(gè)更微妙的標(biāo)準(zhǔn):

右值引用類型既可以被當(dāng)作左值也可以被當(dāng)作右值,判斷的標(biāo)準(zhǔn)是,如果它有名字,那就是左值,否則就是右值。

在上面的例子中,因?yàn)橛抑狄脁是有名字的,所以x被當(dāng)作左值來處理。

void foo(X&&void foo(X&& x)
{ X anotherX = x; // 調(diào)用X(X const & rhs)}

下面是一個(gè)沒有名字的右值引用被當(dāng)作右值處理的例子:

X&& goo();X x = goo(); // 調(diào)用X(X&& rhs),goo的返回值沒有名字

之所以采用這樣的判斷方法,是因?yàn)椋喝绻试S悄悄地把move語義應(yīng)用到有名字的東西(比如foo中的x)上面,代碼會(huì)變得容易出錯(cuò)和讓人迷惑。

void foo(X&& x){  X anotherX = x;  // x仍然在作用域內(nèi)}

這里的x仍然是可以被后面的代碼所訪問到的,如果把x作為右值看待,那么經(jīng)過X anotherX = x;后,x的內(nèi)容已經(jīng)發(fā)生變化。move語義的重點(diǎn)在于將其應(yīng)用于那些不重要的東西上面,那些move之后會(huì)馬上銷毀而不會(huì)被再次用到的東西上面。所以就有了上面的準(zhǔn)則:如果有名字,那么它就是左值。

那另外一半,“如果沒有名字,那它就是右值”又如何理解呢?上面goo()的例子中,理論上來說goo()所引用的對(duì)象也可能在X x = goo();后被訪問的到。但是回想一下,這種行為不正是我們想要的嗎?我們也想隨心所欲的在左值上面使用move語義。正是“如果沒有名字,那它就是右值”的規(guī)則讓我們能夠?qū)崿F(xiàn)強(qiáng)制move語義。其實(shí)這就是std::move的原理。這里展示std::move的具體實(shí)現(xiàn)還是太早了點(diǎn),不過我們離理解std::move更近了一步。它什么都沒做,只是把它的參數(shù)通過右值引用的形式傳遞下去。

std::move(x)的類型是右值引用,而且它也沒有名字,所以它是個(gè)右值。因此std::move(x)正是通過隱藏名字的方式把它的參數(shù)變?yōu)橛抑怠?/p>

下面這個(gè)例子將展示記住“如果它有名字”的規(guī)則是多么重要。假設(shè)你寫了一個(gè)類Base,并且通過重載拷貝構(gòu)造函數(shù)和賦值操作符實(shí)現(xiàn)了move語義:

Base(Base const & rhs); // non-move semanticsBase(Base&& rhs); // move semantics

然后又寫了一個(gè)繼承自Base的類Derived。為了保證Derived對(duì)象中的Base部分能夠正確實(shí)現(xiàn)move語義,必須也重載Derived類的拷貝構(gòu)造函數(shù)和賦值操作符。先讓我們看下拷貝構(gòu)造函數(shù)(賦值操作符的實(shí)現(xiàn)類似),左值版本的拷貝構(gòu)造函數(shù)很直白:

Derived(Derived const & rhs)  : Base(rhs){  // Derived-specific stuff}

但右值版本的重載卻要仔細(xì)研究下,下面是某個(gè)不知道“如果它有名字”規(guī)則的程序員寫的:

Derived(Derived&& rhs)  : Base(rhs) // 錯(cuò)誤:rhs是個(gè)左值{  // ...}

如果像上面這樣寫,調(diào)用的永遠(yuǎn)是Base的非move語義的拷貝構(gòu)造函數(shù)。因?yàn)閞hs有名字,所以它是個(gè)左值。但我們想要調(diào)用的卻是move語義的拷貝構(gòu)造函數(shù),所以應(yīng)該這么寫:

Derived(Derived&& rhs)  : Base(std::move(rhs)) // good, calls Base(Base&& rhs){  // Derived-specific stuff}

move語義與編譯器優(yōu)化

現(xiàn)在有這么一個(gè)函數(shù):

X foo(){  X x;  // perhaps do something to x  return x;}

一看到這個(gè)函數(shù),你可能會(huì)說,咦,這個(gè)函數(shù)里有一個(gè)復(fù)制的動(dòng)作,不如讓它使用move語義:

X foo(){  X x;  // perhaps do something to x  return std::move(x); // making it worse!}

很不幸的是,這樣不但沒有幫助反而會(huì)讓它變的更糟?,F(xiàn)在的編譯器基本上都會(huì)做返回值優(yōu)化(return value optimization)。也就是說,編譯器會(huì)在函數(shù)返回的地方直接創(chuàng)建對(duì)象,而不是在函數(shù)中創(chuàng)建后再復(fù)制出來。很明顯,這比move語義還要好一點(diǎn)。

所以,為了更好的使用右值引用和move語義,你得很好的理解現(xiàn)在編譯器的一些特殊效果,比如return value optimization和copy elision。并且在運(yùn)用右值引用和move語義時(shí)將其考慮在內(nèi)。Dave Abrahams就這一主題寫了一系列的文章[4]。

完美轉(zhuǎn)發(fā):?jiǎn)栴}

除了實(shí)現(xiàn)move語義之外,右值引用要解決的另一個(gè)問題就是完美轉(zhuǎn)發(fā)問題(perfect forwarding)。假設(shè)有下面這樣一個(gè)工廠函數(shù):

template<typename T, typename Arg>shared_ptr<T> factory(Arg arg){  return shared_ptr<T>(new T(arg));}

很明顯,這個(gè)函數(shù)的意圖是想把參數(shù)arg轉(zhuǎn)發(fā)給T的構(gòu)造函數(shù)。對(duì)參數(shù)arg而言,理想的情況是好像factory函數(shù)不存在一樣,直接調(diào)用構(gòu)造函數(shù),這就是所謂的“完美轉(zhuǎn)發(fā)”。但真實(shí)情況是這個(gè)函數(shù)是錯(cuò)誤的,因?yàn)樗肓祟~外的通過值的函數(shù)調(diào)用,這將不適用于那些以引用為參數(shù)的構(gòu)造函數(shù)。

最常見的解決方法,比如被boost::bind采用的,就是讓外面的函數(shù)以引用作為參數(shù)。

template<typename T, typename Arg>shared_ptr<T> factory(Arg& arg){  return shared_ptr<T>(new T(arg));}

這樣確實(shí)會(huì)好一點(diǎn),但不是完美的?,F(xiàn)在的問題是這個(gè)函數(shù)不能接受右值作為參數(shù):

factory<X>(hoo()); // error if hoo returns by valuefactory<X>(41); // error

這個(gè)問題可以通過一個(gè)接受const引用的重載解決:

template<typename T, typename Arg>shared_ptr<T> factory(Arg const & arg){  return shared_ptr<T>(new T(arg));}

這個(gè)辦法仍然有兩個(gè)問題。首先如果factory函數(shù)的參數(shù)不是一個(gè)而是多個(gè),那就需要針對(duì)每個(gè)參數(shù)都要寫const引用和non-const引用的重載。代碼會(huì)變的出奇的長(zhǎng)。

其次這種辦法也稱不上是完美轉(zhuǎn)發(fā),因?yàn)樗荒軐?shí)現(xiàn)move語義。factory內(nèi)的構(gòu)造函數(shù)的參數(shù)是個(gè)左值(因?yàn)樗忻郑约词箻?gòu)造函數(shù)本身已經(jīng)支持,factory也無法實(shí)現(xiàn)move語義。

右值引用可以很好的解決上面這些問題。它使得不通過重載而實(shí)現(xiàn)真正的完美轉(zhuǎn)發(fā)成為可能。為了弄清楚是如何實(shí)現(xiàn)的,我們還需要再掌握兩個(gè)右值引用的規(guī)則。

完美轉(zhuǎn)發(fā):解決方案

第一條右值引用的規(guī)則也會(huì)影響到左值引用?;叵胍幌拢赾++11標(biāo)準(zhǔn)之前,是不允許出現(xiàn)對(duì)某個(gè)引用的引用的:像A& &這樣的語句會(huì)導(dǎo)致編譯錯(cuò)誤。不同的是,在c++11標(biāo)準(zhǔn)里面引入了引用疊加規(guī)則:

A& & => A&A& && => A&A&& & => A&A&& && => A&&

另外一個(gè)是模版參數(shù)推導(dǎo)規(guī)則。這里的模版是接受一個(gè)右值引用作為模版參數(shù)的函數(shù)模版。

template<typename T>void foo(T&&);

針對(duì)這樣的模版有如下的規(guī)則:

  1. 當(dāng)函數(shù)foo的實(shí)參是一個(gè)A類型的左值時(shí),T的類型是A&。再根據(jù)引用疊加規(guī)則判斷,最后參數(shù)的實(shí)際類型是A&。
  2. 當(dāng)foo的實(shí)參是一個(gè)A類型的右值時(shí),T的類型是A。根據(jù)引用疊加規(guī)則可以判斷,最后的類型是A&&。

有了上面這些規(guī)則,我們可以用右值引用來解決前面的完美轉(zhuǎn)發(fā)問題。下面是解決的辦法:

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){  return shared_ptr<T>(new T(std::forward<Arg>(arg)));}

std::forward的定義如下:

template<class S>S&& forward(typename remove_reference<S>::type& a) noexcept{  return static_cast<S&&>(a);}

上面的程序是如何解決完美轉(zhuǎn)發(fā)的問題的?我們需要討論當(dāng)factory的參數(shù)是左值或右值這兩種情況。假設(shè)A和X是兩種類型。先來看factory的參數(shù)是X類型的左值時(shí)的情況:

X x;factory<A>(x);

根據(jù)上面的規(guī)則可以推導(dǎo)得到,factory的模版參數(shù)Arg變成了X&,于是編譯器會(huì)像下面這樣將模版實(shí)例化:

shared_ptr<A> factory(X& && arg){  return shared_ptr<A>(new A(std::forward<X&>(arg)));}X& && forward(remove_reference<X&>::type& a) noexcept{  return static_cast<X& &&>(a);}

應(yīng)用前面的引用疊加規(guī)則并且求得remove_reference的值后,上面的代碼又變成了這樣:

shared_ptr<A> factory(X& arg){  return shared_ptr<A>(new A(std::forward<X&>(arg)));}X& std::forward(X& a){  return static_cast<X&>(a);}

這對(duì)于左值來說當(dāng)然是完美轉(zhuǎn)發(fā):通過兩次中轉(zhuǎn),參數(shù)arg被傳遞給了A的構(gòu)造函數(shù),這兩次中轉(zhuǎn)都是通過左值引用完成的。

現(xiàn)在再考慮參數(shù)是右值的情況:

X foo();factory<A>(foo());

再次根據(jù)上面的規(guī)則推導(dǎo)得到:

shared_ptr<A> factory(X&& arg){  return shared_ptr<A>(new A(std::forward<X>(arg)));}X&& forward(X& a) noexcept{  return static_cast<X&&>(a);}

對(duì)右值來說,這也是完美轉(zhuǎn)發(fā):參數(shù)通過兩次中轉(zhuǎn)被傳遞給A的構(gòu)造函數(shù)。另外對(duì)A的構(gòu)造函數(shù)來說,它的參數(shù)是個(gè)被聲明為右值引用類型的表達(dá)式,并且它還沒有名字。那么根據(jù)第5節(jié)中的規(guī)則可以判斷,它就是個(gè)右值。這意味著這樣的轉(zhuǎn)發(fā)完好的保留了move語義,就像factory函數(shù)并不存在一樣。

事實(shí)上std::forward的真正目的在于保留move語義。如果沒有std::forward,一切都是正常的,但有一點(diǎn)除外:A的構(gòu)造函數(shù)的參數(shù)是有名字的,那這個(gè)參數(shù)就只能是個(gè)左值。

如果你想再深入挖掘一點(diǎn)的話,不妨問下自己這個(gè)問題:為什么需要remove_reference?答案是其實(shí)根本不需要。如果把remove_reference<S>::type&換成S&,一樣可以得出和上面相同的結(jié)論。但是這一切的前提是我們指定Arg作為std::forward的模版參數(shù)。remove_reference存在的原因就是強(qiáng)迫我們?nèi)ミ@樣做。

已經(jīng)講的差不多了,剩下的就是std::move的實(shí)現(xiàn)了。記住,std::move的用意在于將它的參數(shù)傳遞下去,將它轉(zhuǎn)換成右值。

template<class T>typename remove_reference<T>::type&&std::move(T&& a) noexcept{  typedef typename remove_reference<T>::type&& RvalRef;  return static_cast<RvalRef>(a);}

下面假設(shè)我們針對(duì)一個(gè)X類型的左值調(diào)用std::move。

X x;std::move(x);

根據(jù)前面的模版參數(shù)推導(dǎo)規(guī)則,模版參數(shù)T變成了X&,于是:

typename remove_reference<X&>::type&&std::move(X& && a) noexcept{  typedef typename remove_reference<X&>::type&& RvalRef;  return static_cast<RvalRef>(a);}

然后求得remove_reference的值,并應(yīng)用引用疊加規(guī)則,得到:

X&& std::move(X& a) noexcept{  return static_cast<X&&>(a);}

這就可以了,x變成了沒有名字的右值引用。

參數(shù)是右值的情況由你來自己推導(dǎo)。不過你可能馬上就想跳過去了,為什么會(huì)有人把std::move用在右值上呢?它的功能不就是把參數(shù)變成右值么。另外你可能也注意到了,我們完全可以用static_cast<X&&>(x)來代替std::move(x),不過大多數(shù)情況下還是用std::move(x)比較好。

參考

  1. C++11 from wikipedia
  2. C++ Rvalue References Explained
  3. Lvalues and Rvalues
  4. RValue References: Moving Forward?
  5. A Brief Introduction to Rvalue References
  6. C++11 標(biāo)準(zhǔn)新特性: 右值引用與轉(zhuǎn)移語義
  7. C++11 完美轉(zhuǎn)發(fā)
  8. 《C++0x漫談》系列之:右值引用(或“move語意與完美轉(zhuǎn)發(fā)”)(下)

本文轉(zhuǎn)自:[譯]詳解C++右值引用

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
深入右值引用,move語義和完美轉(zhuǎn)發(fā)
Python中的 * 不是指針,相當(dāng)于不定參數(shù)
C++中的變長(zhǎng)參數(shù)
C++11 bind和function用法
(原創(chuàng))C++11改進(jìn)我們的程序之move和完美轉(zhuǎn)發(fā)
從一維到二維,C 復(fù)數(shù)運(yùn)算總結(jié)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服