日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++11右值引用

發(fā)布時間:2024/3/26 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++11右值引用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 左值和右值
  • 左值,右值與引用的關(guān)系
  • 右值的特殊點
  • 左值引用的應用場景和短板
  • 移動語義
  • 關(guān)于move
  • 完美轉(zhuǎn)發(fā)(&& 和 forward)
  • 總結(jié)

左值和右值

一般沒有明確的定義。
左值有以下性質(zhì):

  • 左值可以取地址
  • 左值可以修改(除了const的左值)
  • 左值可以放在等號左邊,也可以放在等號右邊
  • 右值有以下性質(zhì):

  • 右值不可以取地址
  • 右值不可以修改
  • 右值只能放在等號右邊
  • 最重要的性質(zhì)是左值可以取地址,右值不可以取地址。

    常量,表達式的返回值,非左值的函數(shù)返回值是右值

    如下:

    10 x + y; f(10);

    可以參考下圖的定義:比較好理解和記憶

    C++11對右值進行了嚴格的區(qū)分:
    1.C語言中的純右值,比如:a+b, 100
    2.將亡值。比如:表達式的中間結(jié)果、函數(shù)按照值的方式進行返回。

    總結(jié)一下, 知道以下幾點就足夠了
    1.右值分為純右值和將亡值(中間狀態(tài))
    2.左值可以取地址,右值不可以取地址。

    左值,右值與引用的關(guān)系


    下面代碼對4種情況都舉了例子:

    int main() {//左值引用左值int a;int& b = a;//const的左值引用右值const int& c = 10;//const的左值引用左值const int& f = a;//右值引用右值//int&& d = a; 右值引用左值是非法的,權(quán)限擴大了,右值沒有地址int&& d = 10;//右值引用move后的左值int&& e = move(a);//move相當于把左值變成右值了 }

    右值的特殊點

    右值是不能被修改的,10 = 20這種操作是不允許的。
    但是加了右值引用之后,右值可以被修改。并且右值引用是可以取地址的。效果如下:

    int&& d = 10; d = 20; cout << &d;


    可能會有這種想法,那么加了右值引用的右值不就變得和左值一樣了。
    答案確實是這樣的,后面會講一個叫完美轉(zhuǎn)換的東西,就和這個性質(zhì)有關(guān)系。

    左值引用的應用場景和短板

    左值引用一般都是用來做函數(shù)傳參和函數(shù)返回值。這樣可以減少拷貝次數(shù),提高效率。

    但是有一種情況,左值引用沒有辦法減少拷貝次數(shù)。
    要返回局部對象的時候,沒有辦法將函數(shù)返回值變成左值引用。 必須拷貝。如果不拷貝,就相當于訪問已經(jīng)析構(gòu)了的空間了。

    右值引用的其中一個應用場景就在這里
    ps:并不是說把返回值變成右值引用,右值引用不會做函數(shù)返回值!!!

    移動語義

    移動語義又分為了移動構(gòu)造和移動賦值。在C++11里面,6個默認成員函數(shù)已經(jīng)變到8個了,加多了移動構(gòu)造函數(shù)和移動賦值函數(shù)。

    移動語義需要使用右值引用。

    測試代碼:如果沒有寫移動構(gòu)造的時候,operator+返回的局部對象調(diào)用的是深拷貝來返回的。

    #include <iostream>using namespace std; class String { public:String(char* str = (char*)""){if (nullptr == str)str = (char*)"";_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s): _str(new char[strlen(s._str) + 1]){cout << "String(const String& s)" << ' ' << "深拷貝" << endl;strcpy(_str, s._str);}void swap(String& s){std::swap(_str, s._str);}/*String(String&& s){cout << "String(String&& s) " << "移動語義" << endl;_str = (char*)"";swap(s);}*/String& operator=(String&& s){cout << "String& operator=(String&& s) " << "移動語義" << endl;_str = (char*)"";swap(s);}String& operator=(const String& s){if (this != &s){cout << "String& operator=(const String& s) " << "深拷貝" << endl;char* pTemp = new char[strlen(s._str) + 1];strcpy(pTemp, s._str);delete[] _str;_str = pTemp;}return *this;}String operator+(const String& s){char* pTemp = new char[strlen(_str) + strlen(s._str) + 1];strcpy(pTemp, _str);strcpy(pTemp + strlen(_str), s._str);String strRet(pTemp);return strRet;}~String(){if (_str) delete[] _str;} private:char* _str; };int main() {String s1((char*)"hello");String s2((char*)"world");String s3(s1 + s2); }

    原理如下圖:

    -----------------------------------手動分割線----------------------------------------
    上面講的是沒有移動構(gòu)造函數(shù)情況下:現(xiàn)在我們加上移動構(gòu)造函數(shù)。

    移動構(gòu)造函數(shù)寫法:
    1.參數(shù)是右值引用
    2.交換當前對象和右值引用的所有資源

    移動構(gòu)造和拷貝構(gòu)造的區(qū)別在于:拷貝構(gòu)造要多開一塊空間,移動構(gòu)造不需要。


    移動這個詞很形象,就是把資源不斷的移動到最終的對象上

    String(String&& s) {cout << "String(String&& s) " << "移動語義" << endl;_str = nullptr;swap(s); }

    再次運行

    原理:


    總結(jié)一下:

    關(guān)于move

    move就是把左值變成右值的一個函數(shù)。它并不搬移任何東西,唯一的功能就是將一個左值強制轉(zhuǎn)化為右值引用,然后實現(xiàn)移動語義。
    也就是說:只要你不調(diào)用移動構(gòu)造或者移動賦值,左值的值就不會被移動。

    一旦發(fā)生了移動拷貝,a的字符串就沒有了。

    完美轉(zhuǎn)發(fā)(&& 和 forward)

    完美轉(zhuǎn)發(fā)是指一個模板函數(shù),接收到不同的引用參數(shù),可以調(diào)用不同的函數(shù)去執(zhí)行。

    void f(int&& t) {cout << "右值引用" << endl; }void f(int& t) {cout << "左值引用" << endl; }void f(const int& t) {cout << "const左值引用" << endl; }template<class T> void perfectForward(T&& t) {//f(forward<T>(t));f(t); }int main() {int&& a = 10;int& b = a;const int& c = a;perfectForward(10);perfectForward(b);perfectForward(c); }

    要說兩點:

    template<class T> void perfectForward(T&& t)

    上面代碼里面的模板T&& t并不是說接收的是右值引用,在模板后面加上**&&代表的是萬能引用,既能接收左值引用,也可以接收右值引用。**


    必須要加上forward< T >(t)這個函數(shù)。我們上面說過,右值在被引用的瞬間就變成左值了,如果不加forward,右值引用在繼續(xù)傳參的時候右值引用的類型就會變成左值引用

    因此只要用右值引用傳參,就一定要用forward< T >,否則傳的就是左值引用。

    總結(jié)

    C++11中右值引用主要有以下作用:

  • 實現(xiàn)移動語義(移動構(gòu)造與移動賦值)
  • 給中間臨時變量取別名:(string&& s = s1 + s2,表達式的返回值也是右值)
  • 實現(xiàn)完美轉(zhuǎn)發(fā)
  • 總結(jié)

    以上是生活随笔為你收集整理的C++11右值引用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。