C++右值引用和移動(for beginners)

Attention:this blog is a translation of https://www.internalpointers.com/post/c-rvalue-references-and-move-semantics-beginners ,which is posted by @internalpoiners.

一、前言

在我的前一篇文章里擒贸,我解釋了右值背后的邏輯。核心的思想就是:在C++中你總會有一些臨時的、生命周期較短的值,這些值無論如何你都無法改變关串。
令人驚喜的是撼短,現(xiàn)代C++(通常指C++0x或者更高的版本)引入了右值引用(rvalue reference)的概念:它是一個新的可以被綁定到臨時對象的類型,允許你改變他們醉旦。為什么呢?
讓我們先看看下面的代碼:

int x = 666;                    // (1)
int y = x + 5;                  // (2)

std::string s1 = "hello ";
std::string s2 = "world";
std::string s3 = s1 + s2;       // (3)

std::string getString() {
  return "hello world";
}
std::string s4 = getString();   // (4)

在(1)處桨啃,字面常量(literal constant)666是一個右值:它沒有具體的內(nèi)存地址车胡,除了程序運行時的一些臨時寄存器,它需要被存儲在左值x中留待使用优幸。在(4)處也有著類似的情況吨拍,但是這里右值不是硬編碼(hard-coded)的,而是由函數(shù)getString()返回的网杆。然而羹饰,與(1)處一樣,這個臨時值也需要被存儲在一個左值s4中碳却,留待將來使用队秩。
(2)和(3)處看上去更微妙一些:編譯器創(chuàng)建了一個臨時對象來存放+操作符的結(jié)果,作為一個臨時值昼浦,輸出毫無疑問是一個必須被存放在某處的右值馍资。在這里,我分別將結(jié)果放入到ys3中关噪。

二鸟蟹、右值引用的魔力

傳統(tǒng)的C++規(guī)則規(guī)定:只有存儲在const變量(immutable)中的右值才能獲取它的地址乌妙。從技術(shù)上來說,你可以將一個const lvalue綁定(bind)到一個rvalue上建钥√僭希看下面的代碼:

int& x = 666;       // Error
const int& x = 666; // OK

第一個操作是錯誤的,它是一個使用int類型的右值來初始化non-constint&類型的非法操作熊经。第二個操作正確泽艘,當(dāng)然,x是一個常量镐依,你不能改變他匹涮。(譯者按:注意,常量引用只是規(guī)定無法通過該引用改變引用的對象槐壳,如果該對象有其他非常量引用或者指針然低,通過這些改變該對象仍然是合法的)
C++ 0x引入了一個新的類型——右值引用(rvalue reference),通過在類型名后放置&&來表示右值引用务唐。這些右值引用讓你可以改變一個臨時對象的值脚翘,看上去好像他去掉了上面第二行中的const了一樣。
讓我們用這個新玩具來玩耍一番:

std::string   s1     = "Hello ";
std::string   s2     = "world";
std::string&& s_rref = s1 + s2;    // the result of s1 + s2 is an rvalue
  s_rref += ", my friend";           // I can change the temporary string!
std::cout << s_rref << '\n';       // prints "Hello world, my friend"

這里我們創(chuàng)建了兩個簡單的字符串s1s2绍哎,我將它們連接并把結(jié)果放入std::string&& s_rref中。現(xiàn)在s_rref是一個對于臨時對象的一個引用鞋真,或者稱之為右值引用崇堰。這個引用沒有const修飾,所以我可以根據(jù)需求隨意修改他而不需要付出任何代價涩咖。如果沒有右值引用和&&符號海诲,想要完成這一步是不可能的。為了更好地區(qū)分右值引用和一般引用檩互,我們將傳統(tǒng)的C++引用稱作左值引用(lvalue reference)特幔。
乍一看右值引用毫無用處,然而它為移動語義(move semantics)的實現(xiàn)做了鋪墊闸昨,移動語義可以先出提升你的應(yīng)用的表現(xiàn)蚯斯。

三、移動語義——風(fēng)景秀麗的路線

移動語義(以下簡稱move)是一個最佳移動資源的方法饵较,它避免了不必要的歷史對象的拷貝拍嵌,這些都是基于右值引用的。在我看來循诉,理解什么是move最好的方法就是構(gòu)建一個動態(tài)資源(即動態(tài)分配的指針)的包裝類(wrapper class)并且觀察該類的對象被移入移出函數(shù)時發(fā)生了什么横辆。記住,move不只是用于類茄猫!
讓我們來看下面的例子:

class Holder
{
  public:

    Holder(int size)         // Constructor
    {
      m_data = new int[size];
      m_size = size;
    }

    ~Holder()                // Destructor
    {
      delete[] m_data;
    }

  private:

    int*   m_data;
    size_t m_size;
};

這是一個處理動態(tài)內(nèi)存塊的類狈蚤,除了動態(tài)內(nèi)存分配(allocation)部分之外沒什么特別的困肩。當(dāng)你選擇自己管理內(nèi)存時你需要遵守所謂的rule of three。規(guī)則如下:如果你的類定義了下面所說的方法中的一個或者多個脆侮,它最好顯式定義所有的三個方法:

  • 析構(gòu)函數(shù)(destructor)
  • 拷貝構(gòu)造函數(shù)(copy constructor)
  • 拷貝復(fù)制運算符(copy assignment operator)

(如果你不定義這些函數(shù))C++的編譯器會以默認(rèn)的方式生成這些函數(shù)以及構(gòu)造函數(shù)和其他我們現(xiàn)在沒有考慮的函數(shù)锌畸。不幸的是,默認(rèn)的函數(shù)對于處理動態(tài)資源是完全不夠的他嚷。實際上蹋绽,編譯器無法生成向上面那樣的構(gòu)造函數(shù),因為它不知道我們的類的邏輯筋蓖。

1)實現(xiàn)拷貝構(gòu)造函數(shù)

讓我們先依照Rule of Three并實現(xiàn)拷貝構(gòu)造函數(shù)卸耘。正如你所知道的,拷貝構(gòu)造函數(shù)從另外一個已經(jīng)存在的對象來構(gòu)造新的對象粘咖,例如:

Holder h1(10000); // regular constructor
Holder h2 = h1;   // copy constructor
Holder h3(h1);    // copy constructor (alternate syntax)

一個拷貝構(gòu)造函數(shù)可能長成這樣:

Holder(const Holder& other)
{
  m_data = new int[other.m_size];  // (1)
  std::copy(other.m_data, other.m_data + other.m_size, m_data);  // (2)
  m_size = other.m_size;
}

這里我使用一個已經(jīng)存在的對象other來初始化一個新的Holder對象蚣抗,我創(chuàng)建了一個同樣大小的數(shù)組并且我將other里面m_data的數(shù)據(jù)拷貝到this.m_data中。

2)實現(xiàn)賦值運算符

現(xiàn)在我們來實現(xiàn)賦值運算符瓮下,它用于將一個已存在的對象替換為另一個已存在的對象翰铡。例如:

Holder h1(10000);  // regular constructor
Holder h2(60000);  // regular constructor
h1 = h2;           // assignment operator

一個賦值運算符的定義可能長這樣:

Holder& operator=(const Holder& other) 
{
  if(this == &other) return *this;  // (1)
  delete[] m_data;  // (2)
  m_data = new int[other.m_size];
  std::copy(other.m_data, other.m_data + other.m_size, m_data);
  m_size = other.m_size;
  return *this;  // (3)
}

首先(1)處避免了將自己賦值給自己(self-assignment),既然我們要用另一個對象來替換當(dāng)前的對象讽坏,我們需要清除當(dāng)前對象中所有的數(shù)據(jù)(2)锭魔,剩下的就和拷貝構(gòu)造函數(shù)中的一樣了。按照慣例路呜,我們返回該對象的引用迷捧。
拷貝構(gòu)造函數(shù)和賦值運算符的關(guān)鍵點就是它們都接受一個const的對象的引用作為參數(shù)并且生成了一個它們所屬類的一個副本。
輸入的對象時常量引用胀葱,當(dāng)然無法改變漠秋!

四、現(xiàn)有類設(shè)計的限制

我們的類類很好抵屿,但是它缺少一些優(yōu)化庆锦。考慮下面的函數(shù):

Holder createHolder(int size)
{
  return Holder(size);
}

它用傳值的方式返回了一個Holder對象轧葛。我們知道搂抒,當(dāng)函數(shù)返回一個值時,編譯器會創(chuàng)建一個臨時且完整的對象(右值)〕海現(xiàn)在燕耿,我們的Holder是一個重量級(heavy-weight)的對象,因為它有著內(nèi)部的內(nèi)存分配姜胖,這是一個相當(dāng)費事的任務(wù)——以現(xiàn)有的類設(shè)計返回這些東西的值會導(dǎo)致多次內(nèi)存分配誉帅,這并不是一個好主意。如何得出這個結(jié)論?讓我們看下面的代碼:

int main()
{
  Holder h = createHolder(1000);
}

createHolder()創(chuàng)建的臨時對象被傳入拷貝構(gòu)造函數(shù)中蚜锨,根據(jù)我們現(xiàn)有的設(shè)計档插,拷貝構(gòu)造函數(shù)通過拷貝臨時對象的數(shù)據(jù)分配了它自己的m_data指針。這里有兩次內(nèi)存分配:

  • 創(chuàng)建臨時對象
  • 拷貝構(gòu)造函數(shù)調(diào)用

同樣的拷貝過程發(fā)生在賦值操作符中:

int main()
{
  Holder h = createHolder(1000); // Copy constructor
  h = createHolder(500);         // Assignment operator
}

我們的賦值運算符清除了對象的內(nèi)存亚再,然后通過從臨時對象中拷貝數(shù)據(jù)郭膛,為賦值的對象從頭開始分配新的內(nèi)存。在這里也有兩次內(nèi)存分配:

  • 臨時對象創(chuàng)建
  • 調(diào)用賦值運算符

拷貝的次數(shù)太多了氛悬!我們已經(jīng)有了一個完整的(fully-fledged)臨時對象则剃,它由createHolder()函數(shù)創(chuàng)建。它是一個右值如捅,如果在下一個指令前不被使用將會消失棍现。所以為什么在構(gòu)造或者復(fù)制時我們不使用move而是選擇重復(fù)的拷貝呢?
在上古C++中镜遣,我們沒辦法做這樣的優(yōu)化己肮,返回一個重量級對象的值是無用的。幸運的是悲关,在C++11后谎僻,我們可以(并且鼓勵)使用move來優(yōu)化我們的類。簡而言之寓辱,我們將從現(xiàn)有的對象處偷取他們的數(shù)據(jù)而不是做一些毫無意義的克隆艘绍。不要拷貝,總是使用move秫筏,因為移動的代價更加的低鞍盗。

五、用右值引用實現(xiàn)move semantics

讓我們用move來為我們的類增光添彩跳昼!我們的想法就是增加新的版本的拷貝構(gòu)造函數(shù)和賦值運算符,這樣我們就可以將臨時對象的數(shù)據(jù)直接偷過來肋乍。“偷”的意思是改變對象中數(shù)據(jù)的擁有者鹅颊,我們怎么修改一個臨時變量呢?當(dāng)然是使用右值引用墓造!
在這里我們通常遵守另一個C++規(guī)則——Rule of Five堪伍。它是Rule of Three的擴(kuò)展,額外聲明了一個規(guī)則:任何需要move的類都要聲明兩個額外的成員函數(shù):

  • 移動構(gòu)造函數(shù)(move constructor):通過從臨時對象偷取數(shù)據(jù)來構(gòu)建一個新的對象
  • 移動賦值運算符(move assignment operator):通過從臨時對象偷取數(shù)據(jù)來替換已有對象的數(shù)據(jù)

1)實現(xiàn)移動構(gòu)造函數(shù)

一個典型的移動構(gòu)造函數(shù):

Holder(Holder&& other)     // <-- rvalue reference in input
{
  m_data = other.m_data;   // (1)
  m_size = other.m_size;
  other.m_data = nullptr;  // (2)
  other.m_size = 0;
}

它使用一個右值引用來構(gòu)造Holder對象觅闽,關(guān)鍵部分:作為一個右值引用帝雇,我們可以修改它,所以讓我們先偷他的數(shù)據(jù)(1)蛉拙,然后將它設(shè)置為nullptr(2)尸闸。這里沒有深層次的拷貝,我們僅僅移動了這些資源。將右值引用的數(shù)據(jù)設(shè)置為nullptr是很重要的吮廉,因為一旦臨時對象走出作用域苞尝,它就會調(diào)用析構(gòu)函數(shù)中的delete[] m_data,記住了嗎宦芦?通常來說宙址,為了讓代碼看上去更加的整潔,最好讓被偷取的對象的數(shù)據(jù)處于一個良好定義的狀態(tài)调卑。

六抡砂、實現(xiàn)移動賦值運算符

移動賦值運算符有著同樣的邏輯:

Holder& operator=(Holder&& other)     // <-- rvalue reference in input  
{  
  if (this == &other) return *this;

  delete[] m_data;         // (1)

  m_data = other.m_data;   // (2)
  m_size = other.m_size;

  other.m_data = nullptr;  // (3)
  other.m_size = 0;

  return *this;
}

我們先清理已有對象的數(shù)據(jù)(1),再從其它對象處偷取數(shù)據(jù)(2)恬涧。別忘了把臨時對象的數(shù)據(jù)設(shè)置為正確的狀態(tài)注益!剩下的就是常規(guī)的賦值運算所做的操作。
既然我們有了新的方法气破,編譯器就會檢測你到底是在使用臨時對象(右值)創(chuàng)建一個對象還是使用常規(guī)的對象(左值)聊浅,并且它會根據(jù)檢測的結(jié)果觸發(fā)更加合適的構(gòu)造函數(shù)(或者運算符)。例如:

int main()
{
  Holder h1(1000);                // regular constructor
  Holder h2(h1);                  // copy constructor (lvalue in input)
  Holder h3 = createHolder(2000); // move constructor (rvalue in input) (1) 

  h2 = h3;                        // assignment operator (lvalue in input)
  h2 = createHolder(500);         // move assignment operator (rvalue in input)
}

七现使、何時低匙、何處使用move semantics

move提供了一個更加智能的傳遞重量級對象的方法。你只需要創(chuàng)建你的重量級資源一次然后再任何需要的地方移動即可碳锈。就像我之前說的顽冶,move不只是用于類,只要在你需要改變一個資源的擁有者時都可以使用move售碳。**記住强重,跟指針不一樣的是,move不會分享任何東西贸人,如果對象A從對象B中偷去了數(shù)據(jù)间景,對象B中的數(shù)據(jù)就不再存在了,因此也就不再合法了艺智。我們知道在處理臨時對象時這沒有問題倘要,但是在從常規(guī)對象身上偷取數(shù)據(jù)時就需要慎重了。

1)我嘗試了你的代碼:移動構(gòu)造函數(shù)從來沒有被調(diào)用十拣!

你是對的封拧,如果你運行上面的最后一個代碼,你會注意到移動構(gòu)造函數(shù)在(1)處沒有被調(diào)用夭问,常規(guī)的構(gòu)造函數(shù)被調(diào)用了泽西。這是因為一個被稱作Return Value Optimization(RVO)的技法。現(xiàn)代編譯器能夠檢測出你返回了一個對象的值缰趋,并且為此應(yīng)用一種返回的快捷方式來避免無意義的拷貝捧杉。
你可以讓編譯器不使用這個優(yōu)化陕见。例如,GCC支持fno-elide-constructors標(biāo)記糠溜,用這個標(biāo)記來編譯程序?qū)⑹沟脴?gòu)造函數(shù)和析構(gòu)函數(shù)的調(diào)用次數(shù)明顯提高淳玩。

2)為什么有了RVO我們還需要自己實現(xiàn)move semantics?

RVO僅僅針對返回值(輸出)非竿,不包括函數(shù)參數(shù)(輸入)蜕着。有許多地方你會將可移動的對象作為輸入?yún)?shù)傳入函數(shù),這時候就是移動構(gòu)造函數(shù)和移動賦值運算符發(fā)揮作用的時候了红柱。標(biāo)準(zhǔn)庫(Standard Library)在升級到C++11后承匣,所有的算法和容器都被擴(kuò)展以支持move。所以如果你使用符合Rule of Five的類和標(biāo)準(zhǔn)庫锤悄,你將會獲得重要的優(yōu)化提升韧骗。

八、我可以移動左值嗎零聚?

是的袍暴,通過標(biāo)準(zhǔn)庫中的工具函數(shù)std::move,你可以移動左值隶症。它被用來將左值轉(zhuǎn)化為右值政模,假設(shè)我們想要從一個左值盜取數(shù)據(jù):

int main()
{
  Holder h1(1000);     // h1 is an lvalue
  Holder h2(h1);       // copy-constructor invoked (because of lvalue in input)
}

由于h2接收了一個左值,拷貝構(gòu)造函數(shù)被調(diào)用蚂会。我們需要強(qiáng)制調(diào)用移動構(gòu)造函數(shù)從而避免無意義的拷貝淋样,所以我們這樣做:

int main()
{
  Holder h1(1000);           // h1 is an lvalue
  Holder h2(std::move(h1));  // move-constructor invoked (because of rvalue in input)
}

在這里,std::move將左值h1轉(zhuǎn)化為一個右值:編譯器看見輸入變成了右值胁住,所以調(diào)用了移動構(gòu)造函數(shù)趁猴。h2將會在構(gòu)造時從h1處偷取數(shù)據(jù)。

九彪见、最終的筆記和可能的提升

這篇文章很長但是我僅僅抓住了move的表象儡司。下面列出的是我會在未來深入研究的額外概念。

1)在基礎(chǔ)的Holder類中我們使用了RAII

Resource Acquisition Is Initialization(RAII)是一個C++技術(shù)余指,你可以在資源(文件枫慷、socket、數(shù)據(jù)庫連接浪规、分配的內(nèi)存等)周圍包裝類。這些資源可以在類的構(gòu)造函數(shù)中初始化并在類的析構(gòu)函數(shù)中清除探孝,這會避免資源泄露笋婿。

2)用noexcept標(biāo)記你的移動構(gòu)造函數(shù)和移動賦值運算符

C++11關(guān)鍵詞noexcept表示這個函數(shù)不會拋出異常。一些人認(rèn)為移動構(gòu)造函數(shù)和移動賦值運算符永遠(yuǎn)不要拋出異常顿颅。這是合理的缸濒,因為除了復(fù)制數(shù)據(jù)和和設(shè)置nullptr之外(這些都是不會拋出異常的操作)不需要分配內(nèi)存或者做其它工作。

3)使用copy-and-swap的更深入的優(yōu)化和更好的異常安全性

Holder中所有的構(gòu)造函數(shù)和賦值運算符都充滿了重復(fù)的操作,這不是很好庇配。此外斩跌,如果在拷貝運算符中進(jìn)行(內(nèi)存)分配時,如果拋出了異常捞慌,那么源對象就會變成一個不好的狀態(tài)耀鸦。copy-and-swap解決了這兩個問題,但是增加了一個新方法啸澡。

4)perfect forwarding

這項技術(shù)允許你在多個模板和非模板函數(shù)之間移動數(shù)據(jù)袖订,而不需要強(qiáng)類型轉(zhuǎn)換。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嗅虏,一起剝皮案震驚了整個濱河市洛姑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌皮服,老刑警劉巖楞艾,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異龄广,居然都是意外死亡硫眯,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門蜀细,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舟铜,“玉大人,你說我怎么就攤上這事奠衔∽慌伲” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵归斤,是天一觀的道長痊夭。 經(jīng)常有香客問我,道長脏里,這世上最難降的妖魔是什么她我? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮迫横,結(jié)果婚禮上番舆,老公的妹妹穿的比我還像新娘。我一直安慰自己矾踱,他們只是感情好恨狈,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著呛讲,像睡著了一般禾怠。 火紅的嫁衣襯著肌膚如雪返奉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天吗氏,我揣著相機(jī)與錄音芽偏,去河邊找鬼。 笑死弦讽,一個胖子當(dāng)著我的面吹牛污尉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坦袍,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼十厢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了捂齐?” 一聲冷哼從身側(cè)響起蛮放,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奠宜,沒想到半個月后包颁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡压真,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年娩嚼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滴肿。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡岳悟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泼差,到底是詐尸還是另有隱情贵少,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布堆缘,位于F島的核電站滔灶,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏吼肥。R本人自食惡果不足惜录平,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缀皱。 院中可真熱鬧斗这,春花似錦、人聲如沸啤斗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽争占。三九已至燃逻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間臂痕,已是汗流浹背伯襟。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留握童,地道東北人姆怪。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像澡绩,于是被迫代替她去往敵國和親稽揭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 本文根據(jù)眾多互聯(lián)網(wǎng)博客內(nèi)容整理后形成隙轻,引用內(nèi)容的版權(quán)歸原始作者所有倚聚,僅限于學(xué)習(xí)研究使用齿拂,不得用于任何商業(yè)用途。 左...
    深紅的眼眸閱讀 11,276評論 1 12
  • 1. C++基礎(chǔ) 大多數(shù)編程語言通過兩種方式來進(jìn)一步補(bǔ)充其基本特征1)賦予程序員自定義數(shù)據(jù)類型的權(quán)利揪胃,從而實現(xiàn)對語...
    王偵閱讀 755評論 0 3
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,516評論 1 51
  • 右值引用是C++11中新增的一種新的引用類型,它可以通過減少內(nèi)存的重復(fù)申請氛琢、拷貝和釋放喊递,有效的提高C++程序的性能...
    georgeguo閱讀 1,974評論 0 4
  • 兒子在寫作業(yè),陪他的空檔我來完成今天的文字阳似,感覺蠻好的骚勘。 今天讀的女子是蕭紅,認(rèn)識蕭紅是從小學(xué)課文《祖...
    王艷粉閱讀 381評論 0 0