C++11?右值引用的使用場景分析
前言
c++11中新增了右值引用的語法,本章主要說明左值引用和右值引用的使用場景
在我們了解左值引用和右值引用前,我們要先來理解一下左值和右值分別是什么
1.左值and右值
左值是一個表示數(shù)據(jù)的表達(dá)式,我們可以獲取它的地址,有持久狀態(tài)存儲在內(nèi)存當(dāng)中,變量名,指針等,只要是可以取到地址的表達(dá)式都是左值
右值也是一個數(shù)據(jù)表達(dá)式,一般是字面常量或者創(chuàng)建的臨時(shí)對象
核心區(qū)別:是否可以拿到地址,可以取地址就是左值 取不到地址就是右值

2.左值引用and右值引用
我們知道引用其實(shí)就是起了一個別名 左值引用和右值引用也就是起別名
一個& 就是左值引用 兩個&&就是右值引用
注意:左值引用不能直接引用右值 const左值可以引用右值
右值引用不能直接引用左值 右值引用可以引用move(左值)
move是一個函數(shù) 底層我們可以理解就是將左值強(qiáng)轉(zhuǎn)成右值 但它的屬性還是左值


引用可以延長生命周期
我們知道臨時(shí)變量的生命周期很短,只有執(zhí)行的那一行代碼
const左值可以延長生命周期 右值引用可以延長生命周期
但是普通左值引用不可以延長生命周期,這是因?yàn)榕R時(shí)對象是右值,普通左值引用綁定右值,就可能會出現(xiàn)對已經(jīng)銷毀的對象做無效引用
注意:這里的延長生命周期是只在當(dāng)前的棧幀有效,一旦函數(shù)運(yùn)行完畢,進(jìn)行釋放,被延長的生命周期的臨時(shí)對象也就被銷毀了,延長的生命周期只在當(dāng)前的作用域有效?。。?!
3.參數(shù)匹配
c++98當(dāng)我們實(shí)現(xiàn)一個const左值引用作為參數(shù),那么傳左值和右值都可以
c++11新增了右值引用,當(dāng)我們進(jìn)行傳參,編譯器就會找到相對最匹配的函數(shù)繼續(xù)傳參?。?/p>
右值引用變量在用于表達(dá)式的時(shí)候?qū)傩允亲笾?/p>


4.左值引用和右值引用的使用場景
左值引用的使用場景:
當(dāng)函數(shù)的參數(shù)是左值引用 可以減少拷貝 因?yàn)樗皇且粋€別名 左值引用傳返回值得到時(shí)候 也可以減少拷貝 也可以修改實(shí)參 左值引用可以解決大量的拷貝效率問題 但是有些場景不能使用傳左值引用返回
我們來舉個例子 就是如果在當(dāng)前棧幀中創(chuàng)建臨時(shí)對象,我們就需要傳值返回,這種消耗是很大的!

在c++11 右值引用還沒有出來時(shí),編譯器對此進(jìn)行了優(yōu)化,不同的編譯器優(yōu)化可能不同
我們來看一下編譯器優(yōu)化 雖然說最終優(yōu)化只有一次構(gòu)造 但是還是有構(gòu)造 會造成資源消耗

還有一種情況 拷貝構(gòu)造+拷貝賦值

針對于以上的這種情況 我們使用C++11的右值使用就可以很好的解決這個問題
5.移動構(gòu)造和移動賦值
移動構(gòu)造類似拷貝構(gòu)造,移動構(gòu)造函數(shù)的第一個參數(shù)必須是該類類型的右值引用
這個構(gòu)造不同于拷貝構(gòu)造,拷貝構(gòu)造會進(jìn)行深拷貝,移動構(gòu)造是資源進(jìn)行轉(zhuǎn)移??!不會進(jìn)行深拷貝
// 移動構(gòu)造
string(string&& s)
{
cout << "string(string&& s) -- 移動構(gòu)造" << endl;
swap(s);
}就上述場景來看,無論編譯器怎么優(yōu)化,最終還是有一次拷貝,但c++11引入了右值引用,就可以很好的解決這個問題,這里的swap就是進(jìn)行資源轉(zhuǎn)移

移動賦值是賦值運(yùn)算符重載 移動賦值函數(shù)要求第一個參數(shù)必須是該類型的右值引用
它的本質(zhì)也是進(jìn)行資源轉(zhuǎn)移 并不會進(jìn)行深拷貝,這樣就可以減少深拷貝 提高資源利用效率
/// 移動賦值
string& operator=(string&& s)
{
cout << "string& operator=(string&& s) -- 移動賦值" << endl;
swap(s);
return *this;
}
6.引用折疊and萬能引用
C++11中不可以直接將左值引用和右值引用寫在一起 int& && x = i; 這種寫法是錯誤的
我們需要通過模版或者typedef的操作 構(gòu)成引用的引用
C++11規(guī)定 右值引用的右值引用折疊后是右值引用 其他的組合折疊后都是左值引用
我們通過一些例子來理解一下:


萬能引用其實(shí)就是一個模版 將參數(shù)設(shè)計(jì)成T&& 既可以接受左值引用又可以接受右值引用
template<class T>
void Function(T&& t)
{
Fun(t);
}
7.完美轉(zhuǎn)發(fā)
完美轉(zhuǎn)發(fā)的核心要點(diǎn)就是保持當(dāng)前對象的屬性

template<class T>
void Function(T&& t)
{
//Fun(t);
Fun(forward<T>(t));
}完美轉(zhuǎn)發(fā)的使用場景:我們知道變量表達(dá)式都是左值屬性 當(dāng)一個右值被右值引用綁定后 右值引用變量表達(dá)式的屬性是左值 Function的t的屬性是左值 將t傳給Fun,那么只會匹配左值引用的Fun函數(shù),代碼結(jié)果就會出現(xiàn)錯誤 這個時(shí)候我們就需要使用完美轉(zhuǎn)發(fā)保持t的屬性
完美轉(zhuǎn)發(fā)forward的本質(zhì)是一個函數(shù)模版,核心是通過引用折疊實(shí)現(xiàn) 如果說傳給Function的實(shí)參是右值 T被推導(dǎo)int,不進(jìn)行折疊,forward內(nèi)部t被轉(zhuǎn)換成右值引用進(jìn)行返回 如果說傳給Function的實(shí)參是左值,T被推導(dǎo)int&,引用折疊左值引用,forward內(nèi)部t被強(qiáng)轉(zhuǎn)為左值引用返回
到此這篇關(guān)于C++11 右值引用的文章就介紹到這了,更多相關(guān)C++11 右值引用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)Dijkstra算法的示例代碼
迪杰斯特拉算法(Dijkstra)是由荷蘭計(jì)算機(jī)科學(xué)家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是從一個頂點(diǎn)到其余各頂點(diǎn)的最短路徑算法。本文將用C++實(shí)現(xiàn)Dijkstra算法,需要的可以參考一下2022-07-07
C語言實(shí)現(xiàn)動態(tài)版通訊錄的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C語言實(shí)現(xiàn)一個簡單的動態(tài)版通訊錄,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C語言有一定幫助,需要的可以參考一下2022-08-08
C++11?nullptr實(shí)現(xiàn)初始化空指針
避免產(chǎn)生“野指針”最有效的方法,就是在定義指針的同時(shí)完成初始化操作,本文主要介紹了C++11?nullptr初始化空指針,感興趣的可以了解一下2022-01-01
C++定時(shí)器Timer在項(xiàng)目中的使用方法
這篇文章主要給大家介紹了關(guān)于C++定時(shí)器Timer在項(xiàng)目中的基本使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
C++ OpenCV學(xué)習(xí)之圖像像素值統(tǒng)計(jì)
在圖像分析的時(shí)候,我們經(jīng)常需要對單通道圖像的像素進(jìn)行統(tǒng)計(jì)。本文將主要介紹利用C++ OpenCV實(shí)現(xiàn)的圖像像素值統(tǒng)計(jì)的幾種方法,需要的可以參考一下2022-01-01
C++中std::thread{}和std::thread()用法
std::thread{}和std::thread()在C++中都可以用于創(chuàng)建線程對象,但std::thread{}作為C++11引入的統(tǒng)一初始化,更推薦使用,因?yàn)樗踩⒏鬃x,且避免了隱式類型轉(zhuǎn)換2024-11-11

