c++11 右值引用和移動語意

來源:互聯網
上載者:User

標籤:\n   複製建構函式   hello   右值引用   調用   out   err   char   main   

什麼是左值、右值

最常見的誤解:
  等號左邊的就是左值,等號右邊的就是右值
  左值和右值都是針對錶達式而言的,
  左值是指運算式結束後依然存在的持久對象
  右值是指運算式結束時就不再存在的臨時對象
區分:
  能對錶達式進行取地址,則為左值 ;否則為右值


為什麼引入右值引用?
std::vector<String> v;
v.push_back(“hello,world”);

  • 調用 String::String(const char *);
  • 調用 String::String(const String&);
  • 調用 String::~String()

問題癥結在於,臨時對象的構造和析構帶來了不必要的資源拷貝。
如果有一種機制,可以在文法層面識別出臨時對象,在使用臨時物件建構新對象(拷貝構造)的時候,將臨時對象所持有的資源『轉移』到新的對象中,就能消除這種不必要的拷貝。
這種文法機制就是『右值引用』。


左值引用

根據其修飾符的不同,可分為非常量左值引用和常量左值引用

int ia = 10;   int &a = ia;

const int ib = 30;   int &b = ib;

const int &ri = 20;

非常量左值引用只能綁定到非常量左值

常量左值引用可以綁定到所有類型的值,包括 非常量左值、常量左值、右值(根據文法規則,無法區分出右值)

 右值VS臨時對象

vector<int> get_all_scores(){vector<int> vec;vec.push_back(1);vec.push_back(2);return vec;}vector<int> vec =get_all_scores();//這裡實際上調用了三次建構函式

  

右值引用

右值引用 int &&refa;
引入右值引用後,『引用』到『值』的綁定規則也得到擴充:
左值引用可以綁定到左值: int x; int &xr = x;
非常量左值引用不可以綁定到右值: int &r = 0;
常量左值引用可以綁定到左值和右值:int x; const int &cxr = x; const int &cr = 0;
右值引用可以綁定到右值:int &&r = 0;
右值引用不可以綁定到左值:int x; int &&xr = x;
常量右值引用沒有現實意義(畢竟右值引用的初衷在於移動語意,而移動就意味著『修改』)。

移動語意--std::move

編譯器只對右值引用才能調用轉移建構函式和轉移賦值函數,而所有命名物件都只能是左值引用,如果已知一個命名物件不再被使用而想對它調用轉移建構函式和轉移賦值函數,也就是把一個左值引用當做右值引用來使用,怎麼做呢?標準庫提供了函數 std::move,這個函數以非常簡單的方式將左值引用轉換為右值引用。

通過移動語意,我們可以在沒有必要的時候避免複製。


對於右值引用而言,它本身是右值嗎?
樣本
1. 字串的定義

#include <stdio.h>#include <string.h>#include <iostream>#include <vector>#include <string>using std::cout;using std::endl;using std::vector;using std::string;class String{public:String(): _pstr(new char[1]()){}String(const char * pstr): _pstr(new char[strlen(pstr) + 1]()){cout << "String(const char *)" << endl;strcpy(_pstr, pstr);}//複製建構函式String(const String & rhs): _pstr(new char[strlen(rhs._pstr) + 1]()){cout << "String(const String & rhs)" << endl;strcpy(_pstr, rhs._pstr);}     //如果傳遞的是右值,而複製建構函式和移動建構函式同時存在,此時移動建構函式優先執行。//移動建構函式 C++11String(String && rhs): _pstr(rhs._pstr){cout << "String(String && rhs)" << endl;rhs._pstr = NULL;}//移動賦值運算子函數String & operator=(String && rhs){cout << "String & operator=(String && )" << endl;if(this != &rhs){delete [] _pstr;_pstr = rhs._pstr;rhs._pstr = NULL;}return *this;}//賦值運算子函數String & operator=(const String & rhs){cout << "String & operator=(const String&)" << endl;if(this != &rhs){delete [] _pstr;_pstr = new char[strlen(rhs._pstr) + 1]();strcpy(_pstr, rhs._pstr);}return *this;}~String(){delete [] _pstr;cout << "~String()" << endl;}const char * c_str() const{return _pstr;}friend std::ostream & operator<<(std::ostream & os, const String & rhs);private:char * _pstr;};std::ostream & operator<<(std::ostream & os, const String & rhs){os << rhs._pstr;return os;} int test0(void){//vector<String> vec;//vec.push_back("hello,world");String s1("hello,world");cout << "s1 = " << s1 << endl;s1 = String("shenzhen");cout << "s1 = " << s1 << endl;printf("s1‘s address = %p\n", s1.c_str());cout << endl;String s2("wangdao");cout << "s2 = " << s2 << endl;s2 = std::move(s1);//顯式的將一個左值轉換成右值來使用cout << "s2 = " << s2 << endl;printf("s2‘s address = %p\n", s2.c_str());cout << "s1 = " << s1 << endl;cout << "......" << endl;return 0;}void test1(void){int a = 1;int b = 2;&a;&b;//&(a+b);// error, 右值//&(a++);// error, 右值&(++a);int * pFlag = &a;&pFlag;&(*pFlag);//&100;//error,字面值,右值//&string("hello");//error, 右值,匿名對象,string s1("hello");string s2("world");//&(s1 + s2);//error, 右值const int & m = 1;&m;//左值int && n = 1;//右值引用綁定到右值&n;//int && x = a;//error 右值引用無法綁定到左值}void test2(void){//const引用不僅可以綁定到左值,也可以綁定到右值,//const引用無法區分出傳遞過來的參數到底是左值還是右值////C++11引入右值引用,解決該問題//String && ref1 = String("hello,world");String s1("hello");cout << ref1 << endl;const String & ref2 = s1;cout << ref2 << endl;}int main(void){test0();//test1();//test2();return 0;}

  

總結:

非常量左值引用只能綁定到非常量左值,不能綁定到常量左值、非常量右值和常量右值。
  1)如果允許綁定到常量左值和常量右值,則非常量左值引用可以用於修改常量左值和常量右值,
這明顯違反了其常量的含義。
  2) 如果允許綁定到非常量右值,則會導致非常危險的情況出現,因為非常量右值是一個臨時對象,
非常量左值引用可能會使用一個已經被銷毀了的臨時對象。

 

c++11 右值引用和移動語意

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.