亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

淺析C++11中的右值引用、轉移語義和完美轉發

2020-05-23 14:00:40
字體:
來源:轉載
供稿:網友

1. 左值與右值:

    C++對于左值和右值沒有標準定義,但是有一個被廣泛認同的說法:可以取地址的,有名字的,非臨時的就是左值;不能取地址的,沒有名字的,臨時的就是右值.

    可見立即數,函數返回的值等都是右值;而非匿名對象(包括變量),函數返回的引用,const對象等都是左值.

    從本質上理解,創建和銷毀由編譯器幕后控制的,程序員只能確保在本行代碼有效的,就是右值(包括立即數);而用戶創建的,通過作用域規則可知其生存期的,就是左值(包括函數返回的局部變量的引用以及const對象),例如:

int& foo(){int tmp; return tmp;}int fooo(){int tmp; return tmp;}int a=10;const int b;int& temp=foo();//雖然合法,但temp引用了一個已經不存在的對象int tempp=fooo();

以上代碼中,a,temp和foo()都是非常量左值,b是常量左值,fooo()是非常量右值,10是常量右值,有一點要特別注意:返回的引用是左值(可以取地址)!

一般來說,編譯器是不允許對右值進行更改的(因為右值的生存期不由程序員掌握,即使更改了右值也未必可以用),對于內置類型對象尤其如此,但C++允許使用右值對象調用成員函數,雖然允許這樣做,但出于同樣原因,最好不要這么做.

2. 右值引用:

    右值引用的表示方法為

 Datatype&& variable

    右值引用是C++ 11新增的特性,所以C++ 98的引用為左值引用.右值引用用來綁定到右值,綁定到右值以后本來會被銷毀的右值的生存期會延長至與綁定到它的右值引用的生存期,右值引用的存在并不是為了取代左值引用,而是充分利用右值(特別是臨時對象)的建構來減少對象建構和析構操作以達到提高效率的目的,例如對于以下函數:

(Demo是一個類)Demo foo(){   Demo tmp;  return tmp;}

在編譯器不進行RVO(return value optimization)優化的前提下以下操作:

Demo x=foo();

將會調用三次構造函數(tmp的,x的,臨時對象的),相應的在對象被銷毀時也會調用三次析構函數,而如果采用右值引用的方式:

Demo&& x=foo();

那么就不需要進行x的建構,本來本來要被銷毀的臨時對象也會由于x的綁定而將生存期延長至和x一樣(可以理解為x賦予了那個臨時對象一個合法地位:一個名字),就需要提高了效率(代價就是tmp需要占據4字節空間,但這是微不足道的).

    右值引用與左值引用綁定規則:

         常量左值引用可以綁定到常量和非常量左值,常量和非常量右值;

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

         非常量右值引用只能綁定到非常量右值(vs2013也可以綁定到常量右值);

         常量右值引用只能綁定到常量和非常量右值(非常量右值引用只是為了語義的完整而存在,常量左值引用就可以實現它的作用).

         雖然從綁定規則中可以看出常量左值引用也可以綁定到右值,但顯然不可以改變右值的值,右值引用就可以,從而實現轉移語義,因為右值引用通常要改變所綁定的右值,所以被綁定的右值不能為const.

    注意:右值引用是左值!

3. 轉移語義(move semantics):

    右值引用被引入的目的之一就是實現轉移語義,轉移語義可以將資源 ( 堆,系統對象等 ) 的所有權從一個對象(通常是匿名的臨時對象)轉移到另一個對象,從而減少對象構建及銷毀操作,提高程序效率(這在2的例子中已經作了解釋).轉移語義與拷貝語義是相對的.從轉移語義可以看出,實際上,轉移語義并不是新的概念,它實際上已經在C++98/03的語言和庫中被使用了,比如在某些情況下拷貝構造函數的省略(copy constructor elision in some contexts),智能指針的拷貝(auto_ptr “copy”),鏈表拼接(list::splice)和容器內的置換(swap on containers)等,只是還沒有統一的語法和語義支持

    雖然普通的函數和操作符也可以利用右值引用實現轉移語義(如2中的例子),但轉移語義通常是通過轉移構造函數和轉移賦值操作符實現的.轉移構造函數的原型為Classname(Typename&&) ,而拷貝構造函數的原型為Classname(const Typename&) ,轉移構造函數不會被編譯器自動生成,需要自己定義,只定義轉移構造函數也不影響編譯器生成拷貝構造函數,如果傳遞的參數是左值,就調用拷貝構造函數,反之,就調用轉移構造函數.

例如:

class Demo{public:  Demo():p(new int[10000]{};  Demo(Demo&& lre):arr(lre.arr),size(lra.size){lre.arr=NULL;}//轉移構造函數  Demo(const Demo& lre):arr(new int[10000]),size(arr.size){    for(int cou=0;cou<10000;++cou)      arr[cou]=lew.arr[cou];  }private:  int size;  int* arr;}

    從以上代碼可以看出,拷貝構造函數在堆中重新開辟了一個大小為10000的int型數組,然后每個元素分別拷貝,而轉移構造函數則是直接接管參數的指針所指向的資源,效率搞下立判!需要注意的是轉移構造函數實參必須是右值,一般是臨時對象,如函數的返回值等,對于此類臨時對象一般在當行代碼之后就被銷毀,而采用轉移構造函數可以延長其生命期,可謂是物盡其用,同時有避免了重新開辟數組.對于上述代碼中的轉移構造函數,有必要詳細分析一下:

Demo(Demo&& lre):arr(lre.arr),size(lre.size)({lre.arr=NULL;}

lre是一個右值引用,通過它間接訪問實參(臨時對象)的資源來完成資源轉移,lre綁定的對象(必須)是右值,但lre本身是左值;

因為lre是函數的局部對象,”lre.arr=NULL"必不可少,否則函數結尾調用析構函數銷毀lre時仍然會將資源釋放,轉移的資源還是被系統收回.

4. move()函數

    3中的例子并非萬能,Demo(Demo&& lre)的實參必須是右值,有時候一個左值即將到達生存期,但是仍然想要使用轉移語義接管它的資源,這時就需要move函數.

    std::move函數定義在標準庫<utility>中,它的作用是將左值強行轉化為右值使用,從實現上講,std:move等同于static_cast<T&&>(lvalue) ,由此看出,被轉化的左值本身的生存期和左值屬性并沒有被改變,這類似于const_cast函數.因此被move的實參應該是即將到達生存期的左值,否則的話可能起到反面效果.

5. 完美轉發(perfect forwarding)

    完美轉發指的是將一組實參"完美"地傳遞給形參,完美指的是參數的const屬性與左右值屬性不變,例如在進行函數包裝的時候,func函數存在下列重載:

void func(const int);void func(int);void func(int&&);

如果要將它們包裝到一個函數cover內,以實現:

void cover(typename para){  func(para);}

使得針對不同實參能在cover內調用相應類型的函數,似乎只能通過對cover進行函數重載,這使代碼變得冗繁,另一種方法就是使用函數模板,但在C++ 11之前,實現該功能的函數模板只能采用值傳遞,如下:

template<typename T>void cover(T para){  ...  func(para);  ...}

但如果傳遞的是一個相當大的對象,又會造成效率問題,要通過引用傳遞實現形參與實參的完美匹配(包裹const屬性與左右值屬性的完美匹配),就要使用C++ 11 新引入的引用折疊規則:

函數形參       T的類型         推導后的函數形參

T&               A&                A&
T&               A&&              A&
T&&             A&                A&
T&&             A&&              A&&

 因此,對于前例的函數包裝要求,采用以下模板就可以解決:

template<typename T>void cover(T&& para){  ...  func(static_cast<T &&>(para));  ...}

 

如果傳入的是左值引用,轉發函數將被實例化為:

void func(T& && para){  func(static_cast<T& &&>(para));}

應用引用折疊,就為:

void func(T& para){  func(static_cast<T&>(para));}

如果傳入的是右值引用,轉發函數將被實例化為:

void func(T&& &¶){   func(static_cast<T&& &&>(para));}

應用引用折疊,就是:

void func(T&& para){  func(static_cast<T&&>(para));}

對于以上的static_cast<T&&> ,實際上只在para被推導為右值引用的時候才發揮作用,由于para是左值(右值引用是左值),因此需要將它轉為右值后再傳入func內,C++ 11在<untility>定義了一個std::forward<T>函數來實現以上行為,

所以最終版本為

template<typename T>void cover(T&& para){  func(forward(forward<T>(para)));}

std::forward的實現與static_cast<T&&>(para)稍有不同

std::forward函數的用法為forward<T>(para) , 若T為左值引用,para將被轉換為T類型的左值,否則para將被轉換為T類型右值

總結

以上就是關于C++11中右值引用、轉移語義和完美轉發的全部內容,這篇文章介紹的很詳細,希望對大家的學習工作能有所幫助。



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
色综合久久精品亚洲国产| 国产精品爽爽ⅴa在线观看| 精品一区精品二区| 91精品久久久久久久久久久久久久| 国产视频观看一区| 国产一区二区黑人欧美xxxx| 国产男人精品视频| 国产精品久久久久久av福利软件| 亚洲午夜久久久久久久| 欧美在线精品免播放器视频| 国产精品亚洲欧美导航| 亚洲第一精品电影| 久久视频精品在线| 国产99久久精品一区二区 夜夜躁日日躁| 欧美日韩激情美女| 久久久久中文字幕| 亚洲精品国产精品久久清纯直播| 国产在线精品自拍| 国产欧美精品一区二区三区介绍| 北条麻妃久久精品| 日韩免费观看网站| 国产午夜精品全部视频在线播放| 日韩av在线免费观看一区| 国产精品精品视频| 亚洲激情国产精品| 97人人模人人爽人人喊中文字| 亚洲片国产一区一级在线观看| 欧美亚洲在线视频| 色偷偷噜噜噜亚洲男人的天堂| 亚洲激情视频在线播放| 91精品久久久久久久久久另类| 欧美一级黑人aaaaaaa做受| 久久天天躁狠狠躁夜夜躁| 亚洲精品在线视频| 国产精品亚洲第一区| 综合136福利视频在线| 国产91在线高潮白浆在线观看| 国产精品普通话| 精品小视频在线| 国产成人综合久久| 欧洲日本亚洲国产区| 日本在线观看天堂男亚洲| 粗暴蹂躏中文一区二区三区| 日韩亚洲国产中文字幕| 一本一本久久a久久精品综合小说| 欧美精品福利在线| 午夜精品视频网站| 欧美一级电影久久| 欧美视频二区36p| 亚洲一区二区久久久| 亚洲欧美在线播放| 国产丝袜视频一区| 国产精品流白浆视频| 色无极亚洲影院| 亚洲成人激情视频| 精品偷拍各种wc美女嘘嘘| 色婷婷综合久久久久| 欧美激情一区二区三级高清视频| 国产精品免费电影| 国产在线拍揄自揄视频不卡99| 久久天天躁狠狠躁夜夜av| 欧美激情亚洲激情| 欧美日韩国产丝袜美女| 一区二区欧美久久| 久久成人精品一区二区三区| 国产精品扒开腿做爽爽爽视频| 伊人青青综合网站| 欧美有码在线观看视频| 97成人在线视频| 欧美亚洲一区在线| 欧美贵妇videos办公室| 国产原创欧美精品| 亚洲视频自拍偷拍| 欧美日韩性视频| 自拍偷拍亚洲区| 国产精品成av人在线视午夜片| 欧美天天综合色影久久精品| 欧美中文字幕第一页| 欧美精品国产精品日韩精品| 色综合五月天导航| 国外色69视频在线观看| 欧美激情高清视频| 综合久久五月天| 日韩欧美中文字幕在线观看| 欧美一性一乱一交一视频| 欧美日韩激情视频8区| 国产精品视频成人| 久久久久久久久久国产| 国产在线一区二区三区| 精品国产欧美成人夜夜嗨| 久久亚洲精品网站| 日韩性生活视频| 欧美在线欧美在线| 欧美电影在线观看| 国产日韩av高清| 亚洲欧美综合图区| 精品久久久久久久久国产字幕| 亚洲国产日韩精品在线| 欧美性xxxxxxx| 久久激情五月丁香伊人| 国产精品三级美女白浆呻吟| 欧美精品手机在线| 亚洲视频在线观看视频| 欧美重口另类videos人妖| 精品国产1区2区| 日韩欧美有码在线| 亚洲综合国产精品| 国内自拍欧美激情| 欧美性高跟鞋xxxxhd| 欧美综合国产精品久久丁香| 7777kkkk成人观看| 欧美xxxx18性欧美| 国产精品极品尤物在线观看| 清纯唯美亚洲综合| 日韩一区在线视频| 久热精品视频在线观看一区| 中日韩午夜理伦电影免费| 国产精品高清在线| 成人黄色生活片| 国产精品久久久久久久久久三级| www.日韩欧美| 成人精品视频久久久久| 欧美成人国产va精品日本一级| 欧美成人午夜免费视在线看片| 色综合影院在线| 欧美专区日韩视频| 国产香蕉精品视频一区二区三区| 日韩精品久久久久久久玫瑰园| 国产精品精品视频一区二区三区| 久久久这里只有精品视频| 国模精品视频一区二区| 久久久久久久亚洲精品| 欧美亚洲成人精品| 久久影院在线观看| 国产精品日韩在线播放| zzjj国产精品一区二区| 国产精品第三页| 欧美电影免费观看高清| 欧美xxxx18国产| 国产精品黄色影片导航在线观看| 亚洲欧美日韩高清| 国产成人精品a视频一区www| 中国人与牲禽动交精品| 波霸ol色综合久久| 一区二区三区无码高清视频| 成人欧美在线视频| 欧美性猛交xxxx乱大交| 欧美性精品220| 国产精品一区二区久久| 97精品一区二区三区| 久久青草福利网站| 久久久国产精品亚洲一区| 久久亚洲精品中文字幕冲田杏梨| 欧美激情免费观看| 国产免费一区二区三区在线能观看| 成人情趣片在线观看免费| 色青青草原桃花久久综合| 色诱女教师一区二区三区| 国产精品男女猛烈高潮激情| 欧美日韩国产第一页| 欧美日韩亚洲视频一区| 国产精品久久久一区| 亚洲一区二区三区在线免费观看| xvideos国产精品|