C++中的左值與右值

來源

    C++中的左值和右值其實是一個很久遠的概念,但是逐漸到C++11才被重視起來。如今理解這兩個概念對於正確運用C++11的一些特性十分有幫助。

    首要要知道這兩個名詞其實是繼承C語言,C語言中是可以簡單理解爲:左值是賦值語句的左側,右值則不能。然而在C++中,則不能簡單的這麼認爲,但是可以歸納爲:當一個對象被用作右值的時候,用的是對象的值(內容),當對象被用作左值的時候,用的是對象的身份(即在內存中的位置)。

    對於C++中的基本數據類型而言,基本和C語言中的使用相似,但是如果是自定義類型,則不同。

1) 對於基礎類型,右值是不可被修改的,也不可被 const, volatile 所修飾

2) 對於自定義的類型,右值卻允許通過它的成員函數進行修改。

#include <iostream>
using namespace std;
class Test{
public:
    Test(int a):_a(a){ }
    inline void show() const{
        cout<<_a<<endl;
    }
    inline void change(int a) {
        _a=a;
    }
private:
    int _a=3;
};

int main(){
    int lvalue=int(4);
    //int(3)=lvalue;這樣是不行的,int(3)產生一個基礎類型右值,是不可修改的
    cout<<lvalue<<int(5)<<endl;
    Test(5).change(6);//自定義類型右值可以通過成員函數修改
    const Test& tmp=Test(7);
}

    右值的兩個基本特性:

1) 允許調用成員函數。

2) 只能被 const reference 指向。

   一個重要的原則是當需要右值的地方可以用左值來替代,但是不能把右值當成左值(也就是位置)使用。同時,左值與右值最大的區別:左值持久,右值短暫。左值可以有持久的狀態,而右值要麼是字面常量,要麼是表達式求值過程中創建的臨時對象。

左值引用和右值引用

    理解了左值和右值的基本概念和特點,就來區分一下C++11的新特性:左值引用和右值引用。對於常規的引用操作,就是左值引用,注意其不能綁定到要求轉換的表達式、字面常量或是返回右值的表達式。

    右值引用是必須綁定到右值的引用,通過&&來表示,其重要的特質是隻能綁定要一個即將銷燬的對象,即可以綁定到要求轉換的表達式、字面常量或是返回右值的表達式,不能將右值綁定到一個左值上(但是可以通過move來獲得綁定到左值上的右值引用)。

int i = 42; //變量是左值
int &r = i;
int &&rr = i;//錯誤,不能將一個右值綁定到一個左值
int &r2 = i*42;//錯誤,i*42是右值
const int &r3 = i*42//正確,可以將一個const引用綁定在右值上
int &&rr2 = i*42;//正確

std::move

    首先要說明一下,由於移動源對象具有不確定的狀態,對於std::move的使用是有風險的,在使用的時候,一定要確保move對象沒有其他用戶,雖然使用move可以大幅度提升性能,但是也有可能產生難以查找的錯誤。

    一般我們對左值進行拷貝,對右值進行移動。std::move將左值轉換成右值,並賦予它“可移動的語義”

#include <iostream>
#include <utility>
#include <vector>
#include <string>
 
int main()
{
    std::string str = "Hello";
    std::vector<std::string> v;
 
    // 使用 push_back(const T&) 重載,
    // 表示我們將帶來複制 str 的成本
    v.push_back(str);
    std::cout << "After copy, str is \"" << str << "\"\n";
 
    // 使用右值引用 push_back(T&&) 重載,
    // 表示不復制字符串;而是
    // str 的內容被移動進 vector
    // 這個開銷比較低,但也意味着 str 現在可能爲空。
    v.push_back(std::move(str));
    std::cout << "After move, str is \"" << str << "\"\n";
 
    std::cout << "The contents of the vector are \"" << v[0]
                                         << "\", \"" << v[1] << "\"\n";
}

//輸出結果
//After copy, str is "Hello"
//After move, str is ""
//The contents of the vector are "Hello", "Hello"

 

 

參考 《C++ Primer》

https://www.cnblogs.com/catch/p/3500678.html

https://zh.cppreference.com/w/cpp/utility/move

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章