在c++11中所有的值一定屬於左值、純右值和將亡值三種值之一,分別介紹一下這三種型別。
在c++中定義左值與右值的比較標準的方法是根據其可以取位址來判斷。左值就是可以對變數進行取位址或者有名字的變數,按照c語言中的規定也就是說其在記憶體中是被分配了位置;而右值就是不可以取位址、沒有名字的。比如 a = b + c;其中a就是左值、b+c就是右值。
純右值就是c++98中的右值的概念,就是指臨時變數和一些不跟物件關聯的值,比如1+2就是指臨時變數,true和『c』就是一些和物件不相關的值,還有函式的返回值和lamdba函式等
將亡值指的是與右值引用相關的表示式。比如:std::move()的返回值、型別為t&&的函式返回值等。
上述提到了右值引用,右值引用指的是是右值的引用,由於右值一般不存在名字,可以通過引用的方式延長右值的生命週期。比如說如下的**:
t && a =returnvalue();
returnvalue()
函式的返回值就是一種右值,通過利用其返回值將a進行初始化,這樣就等價於」延長」了函式返回值的生命週期。
上述**中也可以使用如下的方式進行初始化:
t a =returnvalue();
這種方式相對於第一種方式多了一次物件的建構函式和析構函式的呼叫,如果返回值占用的記憶體比較大,這樣可能會帶來比較高的成本。注意
std::move()函式會強制將左值轉化為右值引用,等價於乙個型別轉換的操作。一般使用這個方法的場景是在構造乙個新物件的時候,尤其是這個新物件占用了很大的記憶體空間,將乙個左值轉化成為右值引用的時候,可以呼叫移動建構函式,這樣可以降低物件建立帶來的開銷,如果此類中沒有定義移動建構函式,那麼就會呼叫這個類的拷貝建構函式。
t returnrvalue()
t b = returnvalue();
其實b 物件所占用的空間就是a物件的空間。但是rvo/nrvo並不是總是有效的。
之所有存在完美**,其問題實質是:模板引數型別推導在**過程中無法保證左右值的引用問題。而完美**就是在不破壞const屬性的前提下通過增加左右值引用概念和新增引數推導規則解決這個問題。
可以用如下**來幫助理解完美**:
template
void iamforwarding(t t)
在上述**中iamforwarding
會將引數**給iruncodeactually
函式來執行,但是在函式呼叫之間還會存在物件的拷貝,因此可以使用引用來解決該問題,但是又要考慮左值引用和右值引用的問題。可以使用過載來解決該問題,但是這樣會造成**的冗餘。
最終解決這個問題的方法就是使用引用摺疊,在引用摺疊中規定:如果兩個引用中有乙個是左值引用,那麼摺疊的結果是乙個左值引用。否則(即兩個都是右值引用),摺疊的結果是乙個右值引用。,引用摺疊規則如下:
與模板配合使用的例子
#include
using
namespace
std;
void runcode(int && m)
void runcode(int & m)
void runcode(const
int & m)
void runcode(const
int && m)
template
void perfectforward(t &&t)
int main()
簡介C 11中的左值 純右值 將亡值
在c 11以後,表示式按值類別,可分為3種 另,泛左值 generalized lvalue,glvalue 左值 將亡值 右值 right value,rvalue 純右值 將亡值 以下詳細講解 這裡解釋一下 具名的右值引用是左值 看下面的 void foo x a 這裡 a 是乙個具名的右值引用...
c 11之左值引用和右值引用
c 11中增加了右值引用和move語義來避免一些不必要的構造和copy操作,以此來提公升程式的執行效率。首先說左值和右值,他們絕不是簡單的等號左邊和右邊的區別,總結來說 1 左值可以定址,而右值不可以。2 左值可以被賦值,右值不可以被賦值,可以用來給左值賦值。3 左值可變,右值可變 僅對基礎型別適用...
C grammar 左值 右值和將亡值
在c 03中就有相關的概念 通俗的理解 1 能放在等號左邊的是lvalue 2 只能放在等號右邊的是rvalue 3 lvalue可以作為rvalue使用 對於第三點可以舉個例子 int x x 6 x是左值,6是右值 int y y 6 y是左值,6是右值 y x x作為右值,所以左值是可以作為右...