| 網(wǎng)站首頁 | 關于我們 | 開發(fā)優(yōu)勢 | 產(chǎn)品展示 |
| 合作企業(yè) | 新聞動態(tài) | 聯(lián)系我們 | 電話聯(lián)系 |
文章作者:濟南軟件開發(fā) 時間:2016年12月20日
左值(lvalue),右值(rvalue)是一個比較晦澀的概念,有些人可能甚至沒有聽過,但這個概念到了c++11后,卻變得十分重要,它們是理解move(),forward()等新語義的基礎。
那什么是左值右值呢?
左值與右值這兩概念是從c中傳承而來的,在c中,左值指的是能夠出現(xiàn)在等號左邊及右邊的變量(表達式), 右值指的是只能出現(xiàn)在等號右邊的變量(表達式).
復制代碼
int a;
int b;
a = 3;
b = 4;
a = b;
b = a;
//不合法。
3 = a;
a+b = 4;
復制代碼
通常來說,有名字的變量就是左值(如上面例子中的a, b),而由運算(加減乘除,函數(shù)調(diào)用返回值等)產(chǎn)生的中間結(jié)果(沒有名字)就是右值,如上的3+4, a + b等。
我們暫且可以認為:左值就是在程序中能夠?qū)ぶ档臇|西,右值就是沒法取到它的地址的東西(不完全準確)。
如上概念到了c++中,就變得稍有不同。
在c++中,每一個表達式都會產(chǎn)生一個左值,或者右值,相應的,該表達式也就被稱作“左值表達式”,“右值表達式”。對于內(nèi)置的數(shù)據(jù)類型來說(build-in types),左值右值的概念和c的沒有太多不同,不同的地方在于自定義的類型。
而且這種不同比較容易讓人混淆:
1)對于內(nèi)置的類型,右值是不可被修改的(non-modifiable),也不可被const, volatile所修飾(cv-qualitification ignored)
2)對于自定義的類型(user-defined types), 右值卻允許通過它的成員函數(shù)進行修改。
對于1),這是和c是一致的,2)卻是c++中所獨有, 因此,如果你看到c++中如下的寫法,也許有會些驚訝:
復制代碼
class cs
{
public:
cs(int i): i_(i) { cout << "cs(" << i <<") constructor!" << endl; }
~cs() { cout << "cs destructor,i(" << i_ << ")" << endl; }
cs& operator=(const cs& other)
{
i_ = other.i_;
cout << "cs operator=()" << endl;
return *this;
}
int get_i() const { return i_; }
void change(int i) { i_ = i; }
private:
int i_;
};
cs get_cs()
{
static int i = 0;
return cs(i++);
}
int main()
{
// 合法
(get_cs() = cs(2)).change(323);
get_cs() = cs(2);// operator=()
get_cs().change(32);
return 0;
}
復制代碼
這個特性多少有些奇怪,通常來說,c++中的自定義類型是應該設計地盡量和內(nèi)置類型一樣才對的,但這個特性卻偏偏違背了這個原則。
對于這個特性,我們其實可以這樣想,也許會好理解點:自定義類型允許有成員函數(shù),而通過右值調(diào)用成員函數(shù)是被允許的,但成員函數(shù)有可能不是const類型,因此通過調(diào)用右值的成員函數(shù),也就可能會修改了該右值,done!
關于右值,還有一個需要注意的地方是:右值能被const類型的引用所指向
const cs& ref = get_cs();
而且只能被const 類型的reference所指向:
//error
cs& ref = get_cs();
當一個右值被const reference指向時,它的生命周期就被延長了,這個用法我在前面一篇博客里講到過它的相關應用,點這。
這里暗藏邏輯其實就是:右值不能直接轉(zhuǎn)化成左值(但左值可以轉(zhuǎn)化為右值).
上面提到的這兩個特性:
1)允許調(diào)用成員函數(shù)。
2)只能被const reference指向。
導致了一些比較有意思的結(jié)果,比如:
復制代碼
void func(cs& c)
{
cout << "c:" << c.get_i() << endl;
}
//error
func(get_cs());
//正確
func(get_cs() = get_cs());
復制代碼
其中:func(get_cs() = get_cs());能夠正確的原因就在于,cs的成員函數(shù)operator=() 返回的是cs&!
不允許非const reference 引用rvalue并不是完美的,它事實上也引起了一些問題,比如說拷貝構(gòu)造函數(shù)的接口不一致了,這是什么意思呢?
復制代碼
class cs
{
public:
cs& operator=(const cs& c);
};
// 另一種寫法
class cs2
{
public:
cs2& operator=(cs2& c);
};
復制代碼
上面兩種寫法的不同之處就在于參數(shù),一個是const reference,一個是非const.
通常來說,如果不需要修改傳進來的參數(shù),我們往往就按const reference的寫法,但對于copy constructor來說,經(jīng)常是需要修改參數(shù)的值,比如auto_ptr。
復制代碼
// 類似auto_ptr
class auto_ptr
{
public:
auto_ptr(auto_tr& p)
{
ptr_ = p.ptr_;
p.ptr_ = NULL;
}
private:
void* ptr_;
};
復制代碼
所以,對于auto_ptr來說,它的copy constructor傳的參數(shù)是non const reference。
這個種寫法本來應該被鼓勵的,non const reference比const reference更能靈活應對各種情況,從而保持一致的接口類型。
但如果拷貝構(gòu)造函數(shù)寫成這樣子,卻又對rvalue的使用帶來了極大的不變,如前面所講的例子,rvalue不能被non const reference所引用,所以像auto_ptr的這樣的copy constructor就不能傳入rvalue.
//錯誤
auto_ptr p(get_ptr());
// operator=() 同理,錯誤。
auto_ptr p = get_ptr();
這也是auto_ptr很不好用的其中一個原因。
為了解決這個問題,c++11中引入了一種新的引用類型,該種引用類型是專門用來指向rvalue的,有了這種新類型,在c++11中,lvalue 和rvalue的引用類型從此區(qū)分了開來,而在之前,它們是一樣的。
想要了解更多詳情歡迎來電咨詢18678812288
登陸網(wǎng)址:m.h6244.cn。
聯(lián)系人:王經(jīng)理。