C++11的value category(值類別)以及move semantics(移動語意)

來源:互聯網
上載者:User

標籤:保留   構造   沒有   不可   記憶體   相同   back   tor   dash   

轉載請保留以下聲明
  趙宗晟
  出處:http://www.cnblogs.com/zhao-zongsheng/p/value_categories_and_move_semantics.html

C++11之前value categories只有兩類,lvalue和rvalue,在C++11之後出現了新的value categories,即prvalue, glvalue, xvalue。不理解value categories可能會讓我們遇到一些坑時不知怎麼去修改,所以理解value categories對於寫C++的人來說時比較重要的。而理解value categories離不開一個概念——move semantics。瞭解C++11的人我相信都瞭解了std::move,右值引用和移動構造/移動複製等概念,但是對move semantics這個概念的準確定義,還是有很多人比較模糊的。我想通過這篇文章談一談我對value categories和move semantics的理解。首先從move semantics開始。

什麼是move semantics(移動語意)?

semantics是來自語言學的一個概念,翻譯成中文就是“語義”。說到電腦語言,可能有很多人認為他是電腦科學下面的子門類。實際上他是電腦科學和語言學的交叉科目,裡面有很多概念都來自語言學的內容,也有語言學科班的學生之後去做編譯的研究/工作。所以我們先從自然語言入手,通過類比能夠更好地理解move semantics。下面有兩個句子:

  1. 他是飯桶。
  2. 這是飯桶。

這兩句話裡面都有“飯桶”這個詞,但是兩個句子中“飯桶”意思卻不一樣。從文法上來看,這倆都是“<代詞>是飯桶”的形式,只有代詞不一樣,但句子意思卻完全不一樣了。句子1的意思是罵一個人很沒用,句子2的意思是說明這個物體是盛飯的桶。這個例子說明,要理解一個單詞的意思(例如“飯桶”)是要結合句中其他單詞,結合整個句子,甚至要結合前後句理解。

而在C++語言中也是類似的。下面有兩個“句子”(語句):

  1. vec = vector<int>();
  2. vec = another_vec;

其中,vec和another_vec都是vector<int>類型的變數。

這兩個語句都是“vec = XXXX;”的形式,但是語句1是把XXXX移動到變數vec,語句2是把XXXX拷貝給vec。兩個語句中都有“=”運算子,但是語句1中的意思是“移動到”,語句2中的意思是“拷貝給”。所以“=”運算子和整個句子的意思是由XXXX的類型決定的。我們可以說語句1有移動的意思,語句2有拷貝的意思,或者說,語句1中的“=”是移動的意思,語句2中的“=”是拷貝的意思。更正式地說,語句1呈現了移動語意,語句2呈現了拷貝語義,語句1中的“=”呈現了移動語意,語句2中的“=”呈現了拷貝語義。用英文說則是,statement 1 displayed move semantics; statement 2 displayed copy semantics; operator= in statement 1 displayed move semantics; operator= in statement 2 displayed copy semantics。

其實說白了,“移動語意”翻譯成白話就是“移動的意思”。

怎麼理解5種value categories(值類別)?

 C++中的每個運算式都有兩種屬性,一個是類型type,另一個就是值類別value category。每個運算式的值類別一定屬於且僅屬於prvalue (pure rvalue), xvalue, lvalue三種中的一種。prvalue和xvalue統稱為rvalue,xvalue和lvalue統稱為glvalue (generalized lvalue),如所示:

那麼,prvalue,xvalue和lvalue是怎麼定義的?

其實所有運算式都有以下兩種屬性:

  1. 是否有identity(同一性,或者說“有身份”):是否可以與另一個運算式或對象比較,判斷是否是同一個實體。比如,如果有地址,可以比較他們的地址相同;
  2. 是否可以移動:如果出現在賦值,初始化等語句中,是否會使語句呈現移動語意。

於是有:

  1. 有identity,也可以移動的運算式為xvalue;
  2. 有identity,但不能移動的運算式為lvalue;
  3. 沒有identity,但是可以移動的運算式為prvalue;

至於沒有identity,也不可以移動的運算式,在實際應用中不存在這樣的運算式,也沒必要有這樣的運算式。

對於另外兩種值類別,我們可以這麼總結:

  1. 有identity的運算式,值類別為glvalue;
  2. 可以移動的運算式,值類別為rvalue。
分析理解C++標準中值類別的規則

舉例來理解的話,對於xvalue運算式,有這樣的規則:

如果一個運算式是函數調用或重載運算子運算式,且其傳回型別為右值引用,例如 std::move(x),那麼這個運算式是xvalue運算式

對於這個規則,我們可以這麼理解。首先返回一個對象,肯定是要在棧上面預留記憶體空間的,所以這個對象是由identity的。傳回型別是右值引用,所以它會讓使用這個運算式的語句呈現移動語意,所以是可以動的。因此,這個運算式是xvalue運算式。

對於xvalue還有這樣的規則

對象成員運算式,即"a.m",如果 a 是右值且 m 是非參考型別的非待用資料成員,則這個運算式是xvalue運算式

這條規則可以這麼理解,a是右值,也就是可以移動,那麼對於a對象的一部分,m也應當是可以移動的。訪問對象的“.”運算子實際上是指標的位移運算,既然要用指標,那麼肯定是有地址的。因此,這個運算式是xvalue運算式。

再比如:

對象成員運算式,即"a.m",如果 m 是成員枚舉符或非靜態成員函數,則這個運算式是prvalue運算式

不管是靜態枚舉符實際上是一個數字,成員函數實際上是指向程式碼片段的地址,實際上也是一個數字,而且都是在編譯時間期就決定了的數字。cpu對這些數字操作時,這些數字是直接放在指令內部的,或者是放在寄存器中,而不會在記憶體中存在,所以他們是沒有identity的。所以這個運算式是prvalue運算式。

C++標準還定義了很多規則,詳細規定了哪些運算式是prvalue,哪些是xvalue,哪些又是lvalue。這些規則都可以用類似的方法分析並理解,而不需要去死記硬背。

 

C++11的value category(值類別)以及move semantics(移動語意)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.