




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第C++11語法之右值引用的示例講解目錄一、{}的擴(kuò)展initializer_list的講解:二、C++11一些小的更新decltypenullptr范圍for新容器三、右值引用右值真正的用法完美轉(zhuǎn)發(fā)默認(rèn)成員函數(shù)總結(jié)
一、{}的擴(kuò)展
在原先c++的基礎(chǔ)上,C++11擴(kuò)展了很多初始化的方法。
#includeiostream
usingnamespacestd;
structA
int_x;
int_y;
intmain()
inta[]={1,2,3,4,5};
inta1[]{1,2,3,4,5};
int*p=newint[5]{1,2,3,4,5};
Ab={1,2};//初始化
Ab2[5]{{1,1},{2,2},{3,3},{4,4},{5,5}};
A*pb=newA{1,2};
A*pb2=newA[5]{{1,1},{2,2},{3,3},{4,4},{5,5}};
return0;
結(jié)果:
全部初始化正常,vs下指針后面跟數(shù)字可以表示顯示多少個(gè)。
除了上面的new[]{}我認(rèn)為是比較有意義的,很好的解決了new的對(duì)象沒有構(gòu)造函數(shù)又需要同時(shí)創(chuàng)建多個(gè)對(duì)象的場景。
除了上面的,下面的這種方式底層實(shí)現(xiàn)不相同。
initializer_list的講解:
vectorintv{1,2,3,4};
跳轉(zhuǎn)initializer_list實(shí)現(xiàn)
實(shí)際上上面就是通過傳參給initializer_list對(duì)象,這個(gè)對(duì)象相當(dāng)于淺拷貝了外部的{1,2,3,4}的頭指針和尾指針,這樣vector的構(gòu)造函數(shù)就可以通過迭代器遍歷的方式一個(gè)個(gè)的push_back到自己的容器當(dāng)中。上述過程initializer_list是很高效的,因?yàn)樗簧婕皽\拷貝指針和一個(gè)整形。
#includeiostream
templateclassT
classinitializer_list
public:
typedefTvalue_type;
typedefconstTreference;//注意說明該對(duì)象永遠(yuǎn)為const,不能被外部修改!
typedefconstTconst_reference;
typedefsize_tsize_type;
typedefconstT*iterator;//永遠(yuǎn)為const類型
typedefconstT*const_iterator;
private:
iterator_M_array;//用于存放用{}初始化列表中的元素
size_type_M_len;//元素的個(gè)數(shù)
//編譯器可以調(diào)用private的構(gòu)造函數(shù)?。?!
//構(gòu)造函數(shù),在調(diào)用之前,編譯會(huì)先在外部準(zhǔn)備好一個(gè)array,同時(shí)把a(bǔ)rray的地址傳入模板
//并保存在_M_array中
constexprinitializer_list(const_iterator__a,size_type__l)
:_M_array(__a),_M_len(__l){};//注意構(gòu)造函數(shù)被放到private中!
constexprinitializer_list():_M_array(0),_M_len(0){}//emptylist,無參構(gòu)造函數(shù)
//size()函數(shù),用于獲取元素的個(gè)數(shù)
constexprsize_typesize()constnoexcept{return_M_len;}
//獲取第一個(gè)元素
constexprconst_iteratorbegin()constnoexcept{return_M_array;}
//最后一個(gè)元素的下一個(gè)位置
constexprconst_iteratorend()constnoexcept
returnbegin()+_M_len;
而{}初始化,和{}調(diào)用initializer_list組合起來是可以讓初始化變得方便起來的,下面的m0用了initializer_list進(jìn)行初始化,但還是比較麻煩。但m1用了{(lán)}進(jìn)行單個(gè)對(duì)象初始化加initializer_list的組合之后變得方便快捷起來。
#includemap
intmain()
mapint,intm0={pairint,int(1,1),pairint,int(2,2),pairint,int(3,3)};
mapint,intm1={{1,1},{2,2},{3,3}};
return0;
小總結(jié):
一個(gè)自定義類型調(diào)用{}初始化,本質(zhì)是調(diào)用對(duì)應(yīng)的構(gòu)造函數(shù);自定義類型對(duì)象可以使用{}初始化,必須要有對(duì)應(yīng)的參數(shù)類型和個(gè)數(shù);STL容器支持{}初始化,則容器必須有一個(gè)initializer_list作為參數(shù)的構(gòu)造函數(shù)。
二、C++11一些小的更新
auto:
定義變量前加auto表示自動(dòng)存儲(chǔ),表示不用管對(duì)象的銷毀,但是默認(rèn)定義的就是自動(dòng)類型,所以這個(gè)關(guān)鍵字后面就不這樣用了,C++11中改成了自動(dòng)推導(dǎo)類型。
#includecstring
intmain()
inti=10;
autop=
autopf=strcmp;
couttypeid(p).name()endl;
couttypeid(pf).name()endl;
return0;
結(jié)果:
int*
int(__cdecl*)(charconst*,charconst*)
decltype
auto只能推導(dǎo)類型,但推導(dǎo)出來的類型不能用來定義對(duì)象,decltype解決了這點(diǎn),推導(dǎo)類型后可以用來定義對(duì)象。
decltype(表達(dá)式,變量),不能放類型!
#includecstring
intmain()
inti=10;
autop=
autopf=strcmp;
decltype(p)pi;//int*
pi=
cout*piendl;//10
return0;
nullptr
NULL在C中是0,是int類型。C++11添加nullptr表示((void*)0),避免匹配錯(cuò)參數(shù)。
范圍for
支持迭代器就支持范圍for
新容器
array,沒啥用,靜態(tài)的數(shù)組,不支持push_back,支持方括號(hào),里面有assert斷言防止越界,保證了安全。
foward_list,沒啥用,單鏈表,只能在節(jié)點(diǎn)的后面插入。
unordered_map,很有用,后面講
unordered_set,很有用,后面講
三、右值引用
左值
作指示一個(gè)數(shù)據(jù)表達(dá)式(變量名或解引用的指針)。
左值可以在賦值符號(hào)左右邊,右值不能出現(xiàn)在賦值符號(hào)的左邊。
const修飾符后的左值,不能給他賦值,但是可以取他的地址。左值引用就是給左值的引用,給左值取別名。
左值都是可以獲取地址,基本都可以可以賦值
但const修飾的左值,只能獲取地址,不能賦值。
右值?
右值也是一個(gè)數(shù)據(jù)的表達(dá)式,如字面常量,表達(dá)式返回值,傳值返回的函數(shù)的返回值(不能是左值引用返回)。右值不能取地址,不能出現(xiàn)在賦值符號(hào)的左邊。
關(guān)鍵看能不能取地址
給右值取別名就用右值引用,右值引用是左值了,放在賦值符號(hào)的左邊了。
右值不能取地址,但是給右值引用后,引用的變量是可以取地址的,并且可以修改!
右值引用存放的地方在棧的附近。
intmain()
intrra=10;
//不想被修改constintrra
coutrraendl;
rra=100;
return0;
左值引用總結(jié):
左值引用只能引用左值,不能引用右值。但是const修飾的左值引用既可以引用左值,又可以引用右值。在沒有右值引用的時(shí)候就必須采用這種方式了。左值最重要的特征是都可以取地址,即使自定義類型也有默認(rèn)的取地址重載。
右值引用總結(jié):
右值引用只能引用右值,不能引用左值。
右值引用可以引用move以后的左值。
左值引用可以接著引用左值引用,右值引用不可以。
原因:右值引用放到左邊表示他已經(jīng)是一個(gè)左值了,右值引用不能引用左值!
intmain()
inta=10;
intra=a;
intrb=ra;
intrra=10;
intrrb=rra;//err:無法從“int”轉(zhuǎn)換為“int"
return0;
匹配問題:
voidfunc(constinta)
cout"voidfunc(constinta)"endl;
voidfunc(inta)
cout"voidfunc(inta)"endl;
intmain()
inta=10;
func(10);
func(a);
return0;
右值在有右值引用會(huì)去匹配右值引用版本!
右值真正的用法
本質(zhì)上引用都是為了減少拷貝,提高效率。而左值引用解決了大部分的場景,但是左值引用在傳值返回的時(shí)候比較吃力,由右值引用來間接解決。
左值引用在引用傳參可以減少拷貝構(gòu)造,但是返回值的時(shí)候避免不了要調(diào)用拷貝構(gòu)造。
傳參用左值拷貝和右值拷貝都一樣,但是返回值如果用右值引用效率會(huì)高,并且通常左值引用面臨著對(duì)象出了作用域銷毀的問題。所以這就是右值引用的一個(gè)比較厲害的用法。
返回對(duì)象若出了作用域不存在,則用左值引用返回和右值引用返回都是錯(cuò)誤的。
std::move是將對(duì)象的狀態(tài)或者所有權(quán)從一個(gè)對(duì)象轉(zhuǎn)移到另一個(gè)對(duì)象,只是轉(zhuǎn)移,沒有內(nèi)存的搬遷或者內(nèi)存拷貝,所以可以提高利用效率,改善性能。所以當(dāng)作函數(shù)返回值的時(shí)候如果對(duì)象不存在左值引用和右值引用都會(huì)報(bào)錯(cuò)!
場景:返回的對(duì)象在局部域中棧上存在,返回該對(duì)象必須用傳值返回,并且有返回對(duì)象接受,這個(gè)時(shí)候編譯器優(yōu)化,將兩次拷貝構(gòu)造優(yōu)化成一次拷貝構(gòu)造。
測試用的string類
#includeassert.h
namespaceljh
classstring
public:
typedefchar*iterator;
iteratorbegin()
return_str;
iteratorend()
return_str+_size;
string(constchar*str="")
:_size(strlen(str))
,_capacity(_size)
//cout"string(char*str)"endl;
_str=newchar[_capacity+1];
strcpy(_str,str);
//s1.swap(s2)
voidswap(strings)
::swap(_str,s._str);
::swap(_size,s._size);
::swap(_capacity,s._capacity);
//拷貝構(gòu)造
string(conststrings)
:_str(nullptr)
cout"string(conststrings)--深拷貝"endl;
stringtmp(s._str);
swap(tmp);
//賦值重載
stringoperator=(conststrings)
cout"stringoperator=(strings)--深拷貝"endl;
stringtmp(s);
swap(tmp);
return*this;
//移動(dòng)構(gòu)造
/*string(strings)
:_str(nullptr)
,_size(0)
,_capacity(0)
cout"string(strings)--移動(dòng)語義"endl;
swap(s);
//移動(dòng)賦值
stringoperator=(strings)
cout"stringoperator=(strings)--移動(dòng)語義"endl;
swap(s);
return*this;
~string()
delete[]_str;
_str=nullptr;
charoperator[](size_tpos)
assert(pos_size);
return_str[pos];
voidreserve(size_tn)
if(n_capacity)
char*tmp=newchar[n+1];
strcpy(tmp,_str);
delete[]_str;
_str=tmp;
_capacity=n;
voidpush_back(charch)
if(_size=_capacity)
size_tnewcapacity=_capacity==04:_capacity*2;
reserve(newcapacity);
++_size;
_str[_size]='\0';
//stringoperator+=(charch)
stringoperator+=(charch)
push_back(ch);
return*this;
constchar*c_str()const
return_str;
private:
char*_str;
size_t_size;
size_t_capacity;//不包含最后做標(biāo)識(shí)的\0
臨時(shí)變量如果是4/8字節(jié),通常在寄存器當(dāng)中,但是如果是較大的內(nèi)存,會(huì)在調(diào)用方的函數(shù)棧幀中開辟一塊空間用于接受,這就是臨時(shí)對(duì)象。
臨時(shí)對(duì)象存在的必要性
當(dāng)我們不需要接受返回值,而是對(duì)返回的對(duì)象進(jìn)行直接使用,這個(gè)時(shí)候被調(diào)用的函數(shù)中的對(duì)象出了函數(shù)棧幀就銷毀了,所以在棧幀銷毀前會(huì)將對(duì)象拷貝到調(diào)用方棧幀的一塊空間當(dāng)中,我們可以用函數(shù)名對(duì)這個(gè)臨時(shí)對(duì)象直接進(jìn)行操作的(通常不能修改這個(gè)內(nèi)存空間,臨時(shí)變量具有常性)。
分析下面幾組圖片代碼的效率
不可避免的,下面的這個(gè)過程必然要調(diào)用兩次拷貝構(gòu)造,編譯器對(duì)于連續(xù)拷貝構(gòu)造優(yōu)化成不生成臨時(shí)對(duì)象,由func::ss直接拷貝給main的str,我們?nèi)绻挥星懊嫠鶎W(xué)的左值引用,func中的stringss在出了func后銷毀,這個(gè)時(shí)候引用的空間被銷毀會(huì)出現(xiàn)問題,這個(gè)時(shí)候顯得特別無力。
在連續(xù)的構(gòu)造+拷貝構(gòu)造會(huì)被編譯器進(jìn)行優(yōu)化,這個(gè)優(yōu)化要看平臺(tái),但大部分平臺(tái)都會(huì)做這個(gè)處理。
結(jié)果:
即使下面這種情況,在main接受沒有引用的情況下,依舊會(huì)調(diào)用一次拷貝構(gòu)造,跟上面并沒有起到一個(gè)優(yōu)化的作用。
結(jié)果:
解決方案:添加移動(dòng)構(gòu)造,添加一個(gè)右值引用版本的構(gòu)造函數(shù),構(gòu)造函數(shù)內(nèi)部講s對(duì)象(將亡值)的內(nèi)容直接跟要構(gòu)造的對(duì)象交換,效率很高??!
string(strings):_str(nullptr),_size(0),_capacity(0){cout"string(strings)--移動(dòng)語義"endl;swap(s);}
有了移動(dòng)構(gòu)造,對(duì)于上面的案例就變成了一次拷貝構(gòu)造加一次移動(dòng)構(gòu)造。**編譯器優(yōu)化后將ss判斷為將亡值,直接移動(dòng)構(gòu)造str對(duì)象,不產(chǎn)生臨時(shí)對(duì)象了,就只是一次移動(dòng)構(gòu)造,效率升高!!**同理移動(dòng)賦值!
結(jié)果:
下面情況是引用+移動(dòng)構(gòu)造,但是編譯器優(yōu)化就會(huì)判斷ss出了作用域還存在,反而會(huì)拿ss拷貝構(gòu)造str,這個(gè)時(shí)候起不到優(yōu)化的作用!
結(jié)果:
以上采用將對(duì)象開辟在堆上或靜態(tài)區(qū)都能夠采用引用返回解決問題,但是有一個(gè)壞處?
引入多線程的概念,每個(gè)線程執(zhí)行的函數(shù)當(dāng)中若有大量的堆上的數(shù)據(jù)或者靜態(tài)區(qū)的數(shù)據(jù),相當(dāng)于臨界資源變多,要注意訪問臨界資源要加鎖。而每個(gè)棧區(qū)私有棧,會(huì)相對(duì)好些
右值:
1、內(nèi)置類型表達(dá)式的右值,純右值。
2、自定義類型表達(dá)式的右值,將亡值。
將亡值:
string(strings)
:_str(nullptr)
,_size(0)
,_capacity(0)
cout"string(strings)--移動(dòng)語義"endl;
swap(s);
intmain()
ljh::stringstr=func2();
vectorljh::string
v.push_back("1234656");//傳進(jìn)去的就是右值,是用"1234656"構(gòu)造一個(gè)string對(duì)象傳入,就是典型的將亡值
移動(dòng)構(gòu)造:
將亡值在出了生命周期就要銷毀了,構(gòu)造的時(shí)候可以將資源轉(zhuǎn)移過要構(gòu)造的對(duì)象,讓將亡的對(duì)象指向NULL,相當(dāng)于替它掌管資源。移動(dòng)構(gòu)造不能延續(xù)對(duì)象的生命周期,而是轉(zhuǎn)移資源。且移動(dòng)構(gòu)造編譯器不優(yōu)化本質(zhì)是一次拷貝構(gòu)造+一次移動(dòng)構(gòu)造(從將亡值(此時(shí)返回值還是一個(gè)左值)給到臨時(shí)變量),再有臨時(shí)變量給到返回值接受對(duì)象(移動(dòng)構(gòu)造);
編譯器優(yōu)化做第一次優(yōu)化,會(huì)將將亡值當(dāng)作右值,此時(shí)要進(jìn)行兩次移動(dòng)構(gòu)造,編譯器第二次優(yōu)化,直接進(jìn)行一次移動(dòng)構(gòu)造,去掉生成臨時(shí)對(duì)象的環(huán)節(jié)。
只有需要深拷貝的場景,移動(dòng)構(gòu)造才有意義,跟拷貝構(gòu)造一樣,淺拷貝意義不大。
move的真正意義:
表示別人可以將這個(gè)資源進(jìn)行轉(zhuǎn)移走。
intmain()
//為了防止這種情況,也要添加移動(dòng)賦值。
ljh::stringstr1;
str1="123456";
c++11的算法swap的效率跟容器提供的swap效率一樣了。
vector提供的插入的右值引用版本,就是優(yōu)化了傳右值情況,如果C++98則需要拷貝放入,而有右值就可以直接移動(dòng)構(gòu)造。兩個(gè)接口的效率差不多。
大多數(shù)容器的插入接口都做了右值引用版本!!
完美轉(zhuǎn)發(fā)
模板函數(shù)或者模板類用的即萬能引用。
模板中的不代表右值引用,而是萬能引用,其既能接收左值又能接收右值。模板的萬能引用只是提供了能夠接收同時(shí)接收左值引用和右值引用的能力。而forward才能將這種右值特性保持下去。
但是引用類型的唯一作用就是限制了接收的類型,后續(xù)使用中都退化成了左值,
此時(shí)右值在萬能引用成為左值,可能會(huì)造成本身右值可以移動(dòng)構(gòu)造,卻變成左值只能拷貝構(gòu)造了。
Fun(std::forwardT(t));才能夠保證轉(zhuǎn)發(fā)的時(shí)候值的特性
voidFun(intx){cout"左值引用"endl;}
voidFun(constintx){cout"const左值
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 內(nèi)科護(hù)理學(xué)題庫(附參考答案)
- 旅游產(chǎn)品及服務(wù)提供合同
- 農(nóng)機(jī)租賃與維修服務(wù)合作合同書
- 財(cái)務(wù)管理咨詢服務(wù)的協(xié)議
- 江蘇移動(dòng)2025春季校園招聘筆試參考題庫附帶答案詳解
- 2025湖南長沙振望投資發(fā)展有限公司招聘8人筆試參考題庫附帶答案詳解
- 2025廣西玉柴鑄造有限公司實(shí)習(xí)生招聘100人筆試參考題庫附帶答案詳解
- 2025年河南空港數(shù)字城市開發(fā)建設(shè)有限公司第一批社會(huì)公開招聘20人筆試參考題庫附帶答案詳解
- 2025年威海光明電力服務(wù)有限公司招聘(約40人)筆試參考題庫附帶答案詳解
- 2025年3月湖南自由貿(mào)易試驗(yàn)區(qū)臨空產(chǎn)業(yè)投資集團(tuán)有限公司招聘6人筆試參考題庫附帶答案詳解
- 獻(xiàn)血法知識(shí)試題及答案
- 寧波2025年寧波海洋經(jīng)濟(jì)發(fā)展示范區(qū)象山縣高層次緊缺人才選聘筆試歷年參考題庫附帶答案詳解
- T-WSJD 21-2022 內(nèi)鏡儲(chǔ)存干燥柜衛(wèi)生要求
- 煤礦井下輔助運(yùn)輸設(shè)計(jì)規(guī)范
- 2025-2030中國聚丙烯三元共聚物行業(yè)市場發(fā)展趨勢(shì)與前景展望戰(zhàn)略研究報(bào)告
- 2025年上半年蘇州太倉臨港投資發(fā)展集團(tuán)限公司公開招聘工作人員易考易錯(cuò)模擬試題(共500題)試卷后附參考答案
- 工業(yè)自動(dòng)化控制系統(tǒng)調(diào)試與維護(hù)題庫
- 2025屆廣東省佛山市高三語文二模高分范文12篇:“成長最大的悲哀是失去了想象力”
- 2025年合肥高新美城物業(yè)有限公司招聘30人筆試參考題庫附帶答案詳解
- 2025屆陜西省高考適應(yīng)性檢測(三)物理試題+答案
- 23G409先張法預(yù)應(yīng)力混凝土管樁
評(píng)論
0/150
提交評(píng)論