九九热这里直有精品,1区二区三区在线播放,玖玖爱在线观看资源,国产aⅴ综合网,午夜福利男女,日本亚洲欧美三级,日韩无码黄色导航,内射少妇13区,中文字幕高清网

您身邊的軟件定制專家--9年開發(fā)經(jīng)驗為您護航

18678812288
0531-88887250

c++中的左值與右值

文章作者:濟南軟件開發(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)理。

刚察县| 湄潭县| 仙居县| 楚雄市| 房山区| 阿勒泰市| 万山特区| 团风县| 泰来县| 聊城市| 合山市| 西华县| 辽阳县| 洛阳市| 上杭县| 上栗县| 栾川县| 晋州市| 师宗县| 吴忠市| 会同县| 寻乌县| 富阳市| 岐山县| 延庆县| 三门峡市| 太湖县| 泸定县| 新化县| 克拉玛依市| 贺州市| 枣强县| 莎车县| 府谷县| 理塘县| 七台河市| 马关县| 邢台市| 莱芜市| 垫江县| 房山区|