詳解C++中右值引用

98中的引用

  1. 概念
  2. 特性
  3. 引用的使用場景
  4. 三種傳參方式效率的比較
  5. 探索:引用的底層實現方式----->指針
    • T&------>T* const
    • const T&---->const T*const
  6. 引用和指針的區別
引用的總結

11中的右值引用

為什么要有右值引用

為了提高程序運行效率,C++11中引入了右值引用,右值引用也是別名,但其只能對右值引用

int main()
{//右值引用---->引用形式----->只能引用右值int a = 10;int b = 20;//a可以為左值,能放到=號左側的一定是左值//能放到=號右側的不一定是右值a = b;//ra對10的右值引用,ra稱為對10的別名int&& ra = 10;system("pause");return 0;
}

左值與右值

一般認為認為:可以放在=左邊的,或者能夠取地址的稱為左值,只能放在=右邊的,或者不能取地址的稱為右值,但肯定有特殊情況,不一定上述說法就完全正確

int  main()
{const int a = 10;//a = 100; a不能出現在左側//a也不是右值//a能夠取地址cout << &a << endl;//int && ra = a;system("pause");return 0;
}

左值與右值總結

左值與右值不是很好區分,一般認為:

  1. 普通類型的變量,因為有名字,可以取地址,都認為是左值
  2. const修飾的常量,不可修改,只讀類型的,理論上應該按照右值對待,但因為其可以取地址(如果只是const類型常量的定義,編譯器不給其開辟空間,如果對該常量取地址時,編譯器才為其開辟空間),C++11認為其是左值
  3. 如果表達式的運行結果是一個臨時變量或者對象,認為是右值
  4. 如果表達式運行結果或單個變量是一個引用則認為是左值
int b = 10;//為右值
int&& rb = b + 10;
int g_a = 10;int& GetG_A()
{return g_a;
}int main()
{GetG_A() = 10;//下面這行代碼編譯報錯//int && rc = GetG_A();return 0;
}

不能簡單的通過能否放在=左側右側或者取地址來判斷左值或者右值,要根據表達式結果或變量的性質判斷,比如上述:c常量

C++11中的右值

右值引用,顧名思義就是對右值的引用。C++11中,右值由兩個概念組成:純右值和將亡值。

  • 純右值
    純右值是C++98中右值的概念,用于識別臨時變量和一些不跟對象關聯的值。比如:常量、一些運算表達式(1+3)等
  • 將亡值
    聲明周期將要結束的對象。比如:在值返回時的臨時對象。
//將亡值
//值得方式返回
//使用ret--->創建一個臨時變量---->函數運行結束棧空間被回收
int Add(int a, int b)
{int ret = a + b;return ret;
}int main()
{int&& Ret = Add(10,20);return 0;
}

引用與右值引用的比較

//C++98引用
//1. 普通類型得引用
//2. cosnt類型的引用
int main()
{//98中的普通類型的引用不能引用右值int a = 10;int&ra = a;//int&rra = 10;	不行//98中的const引用既可以引用左值也可以引用右值const int&cral = a;const int& cra2 = 10;return 0;
}

C++11中右值引用:只能引用右值,一般情況不能直接引用左值

int main()
{//10純右值,本來只是一個符號,沒有具體空間//右值引用變量r1在定義過程中,編譯器產生了一個臨時變量,r1實際引用的是臨時變量int&& r1=10;r1=100;int a=10;int&& r2=a; //編譯失敗:右值引用不能引用左值return 0;
}

std::move()

C++11中,std::move()函數位于 頭文件中,這個函數名字具有迷惑性,它并不搬移任何東西,唯一的功能就是將一個左值強制轉化為右值引用,通過右值引用使用該值,實現移動語義。 注意:被轉化的左值,其聲明周期并沒有隨著左右值的轉化而改變,即std::move轉化的左值變量不會被銷毀

int main()
{int a = 10;int&& ra = move(a);return 0;
}

右值引用的場景

class String
{
public:String(char* str = ""){if (nullptr == str)str = "";_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s): _str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);}String& operator=(const String& s){if (this != &s){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)];strcpy(pTemp, _str);strcpy(pTemp + strlen(_str), s._str);String strRet(pTemp);delete pTemp;return strRet;}~String(){if (_str) delete[] _str;}
private:char* _str;
};
int main()
{String s1("hello");String s2("world");String s3(s1 + s2);return 0;
}

假設編譯器在返回值位置不優化
上述代碼在加號運算符的重載時,是創建了臨時變量,存儲拼接起來的字符串,返回的時候是按值返回是通過strRet拷貝了一個臨時的對象。函數體內的strRet在return后,已經被銷毀。所以最后s3拷貝構造的時候是通過臨時對象構造的,所以s3也要再創建一個臨時變量,一但拷貝構造好之后,臨時對象就釋放掉了
一個剛釋放一個又申請,有點多此一舉。能不能不讓s3再創建一個臨時對象
我們可以讓s3直接使用返回值的臨時對象。

移動語義

C++11提出移動語義概念:將一個對象中資源移動到另外一個對象的方式

  1. 可以有效的緩解內存的壓力
  2. 提高程序的運行效率,因為不需要開辟空間和釋放空間
//移動構造
//移動構造參數一定不能加cosnt,資源可以轉移出去,但是資源不能清空了
String(String&& s):_str(s._str)
{s._str = nullptr;
}
  1. 移動構造函數參數不能加const類型的右值引用,因為資源無法轉移而導致語義失效
  2. 在C++11中,編譯器會為類默認生成一個移動構造,該移動構造為淺拷貝,因此類中涉及到資源管理時,用戶必須顯示定義自己的移動構造
    在C++11中,拷貝構造/移動構造/賦值/移動賦值函數必須同時提供,或者同時不提供,程序才能保證類同時具有拷貝和移動語義

auto_ptr中的資源轉移

	auto_ptr<int> sp1(new  int);auto_ptr<int> sp2(sp1);//sp1資源給了sp2,但是sp1生命周期還沒有到頭,所以不能被使用

右值引用引用左值

通過move函數把左值轉化為右值。

class Person
{
public:Person(char* name, char* sex, int age): _name(name), _sex(sex), _age(age){}Person(const Person& p): _name(p._name), _sex(p._sex), _age(p._age){}
#if 0Person(Person&& p): _name(p._name), _sex(p._sex), _age(p._age){}
#elsePerson(Person&& p): _name(move(p._name)), _sex(move(p._sex)), _age(p._age){}//移動賦值Person& operator=(Person&&p){return *this;}
#endif
private:String _name;String _sex;int _age;
};
Person GetTempPerson()
{Person pp("prety", "male", 18);return pp;		//pp確實是右值,但是里面的成員變量是當作左值,所以用move把左值轉化為右值
}
int main()
{Person p(GetTempPerson());system("pause");return 0;
}

用move的時機,確定當前變量是將亡值,例如函數返回值

完美轉發

完美轉發是指在函數模板中,完全依照模板的參數的類型,將參數傳遞給函數模板中調用的另外一個函數

void Func(int x)
{// ......
}
template<typename T>
void PerfectForward(T t)
{Fun(t);
}

PerfectForward為轉發的模板函數,Func為實際目標函數,但是上述轉發還不算完美**,完美轉發是目標函數總希望將參數按照傳遞給轉發函數的實際類型轉給目標函數,而不產生額外的開銷**,上述代碼中的Fun(t)只是外部t的一份拷貝,就好像轉發者不存在一樣。

所謂完美:

函數模板在向其他函數傳遞自身形參時,如果相應實參是左值,它就應該被轉發為左值;如果相應實參是右值,它就應該被轉發為右值。這樣做是為了保留在其他函數針對轉發而來的參數的左右值屬性進行不同處理(比如參數為左值時實施拷貝語義;參數為右值時實施移動語義)。

C++11 通過forward函數來實現完美轉發:

void Fun(int &x)	//普通類型引用
{ cout << "lvalue ref" << endl; 
}
void Fun(int &&x)	//普通類型右值引用
{ cout << "rvalue ref" << endl; 
}
void Fun(const int &x)	//const類型普通引用
{cout << "const lvalue ref" << endl; 
}
void Fun(const int &&x)	//const類型的右值引用
{ cout << "const rvalue ref" << endl; 
}//通過函數模板作為轉發函數
template<typename T>
//完美轉發:t是左值---->傳給Fun函數,t應該也是左值
//		   t如果是右值--->傳給Fun函數,t應該是右值
void PerfectForward(T &&t)
{ Fun(std::forward<T>(t)); //forward把t轉化為右值。//Fun(t);
}int main()
{PerfectForward(10); // 10為右值int a;PerfectForward(a); // lvalue refPerfectForward(std::move(a)); // rvalue refconst int b = 8;PerfectForward(b); // const lvalue refPerfectForward(std::move(b)); // const rvalue refreturn 0;
}

foward和move

  • move實現移動語義
  • forward實現完美轉發

右值引用作用

  1. 實現移動語義
  2. 給中間臨時變量取別名
  3. 實現完美轉發
  4. unordered_map 中的構造和插入都有用到右值引用。vectorC++11中的emplace插入(尾插)也用到了右值引用。

pash_back;必須要把對象構造好
emplace:構造加尾插

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383093.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383093.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383093.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++中的lambda表達式和線程庫

98中的一個例子 如果想要對一個數據集合中的元素進行排序&#xff0c;可以使用std::sort方法 #include <algorithm> #include <functional> int main() {int array[] {4,1,8,5,3,7,0,9,2,6};// 默認按照小于比較&#xff0c;排出來結果是升序std::sort(array, a…

文件壓縮(Huaffman樹的概念及其實現)

什么是壓縮 想辦法讓源文件變得更小并能還原。 為什么要進行文件壓縮 文件太大&#xff0c;節省空間提高數據再網絡上傳輸的效率對數據有保護作用—加密 文件壓縮的分類 無損壓縮 源文件被壓縮后&#xff0c;通過解壓縮能夠還原成和源文件完全相同的格式 有損壓縮 解壓縮之…

詳解STL中的空間配置器(SGI版本)

空間配置器 1.什么是空間配置器 為各個容器高效的管理空間(空間的申請與回收)的 2.為什么需要空間配置器 各種容器----->可以存放元素---->底層需要空間 new 申請空間 operator new ---->malloc調用構造函數------完成對象的構造 動態內存管理總結 前面的容器…

【劍指offer】_15數組中重復的數字

題目描述 在一個長度為n的數組里的所有數字都在0到n-1的范圍內。 數組中某些數字是重復的&#xff0c;但不知道有幾個數字是重復的。也不知道每個數字重復幾次。請找出數組中任意一個重復的數字。 例如&#xff0c;如果輸入長度為7的數組{2,3,1,0,2,5,3}&#xff0c;那么對應的…

【劍指offer】_16 構建乘積數組

題目描述 給定一個數組A[0,1,…,n-1],請構建一個數組B[0,1,…,n-1],其中B中的元素B[i]A[0]*A[1]*...*A[i-1]*A[i1]*...*A[n-1]。不能使用除法。 解題思路 設有數組大小為5。 對于第一個for循環 第一步&#xff1a;b[0] 1; 第二步&#xff1a;b[1] b[0] * a[0] a[0] 第三…

【劍指offer】_17正則表達式的匹配

題目描述 請實現一個函數用來匹配包括’.‘和*的正則表達式。模式中的字符’.表示任意一個字符&#xff0c;而*表示它前面的字符可以出現任意次&#xff08;包含0次&#xff09;。 在本題中&#xff0c;匹配是指字符串的所有字符匹配整個模式。例如&#xff0c;字符串"aaa…

大四階段的社會實踐的主要目的是_疫情當前,大三大四的學生“很慘”?大一大二的學生也別松懈...

大四畢業生不容易這次疫情對于高校學生而言&#xff0c;可以說是各有各的難處&#xff0c;“這屆畢業生很慘”更是屢上熱搜。不可否認&#xff0c;大四畢業生確實很不容易&#xff0c;論文答辯、畢業、求職就業等都受到了影響&#xff0c;雖然有困難&#xff0c;但各方都在積極…

【劍指offer】_18 數據流中的中位數

題目描述 如何得到一個數據流中的中位數&#xff1f;如果從數據流中讀出奇數個數值&#xff0c;那么中位數就是所有數值排序之后位于中間的數值。如果從數據流中讀出偶數個數值&#xff0c;那么中位數就是所有數值排序之后中間兩個數的平均值。我們使用Insert()方法讀取數據流…

【劍指offer】_19 滑動窗口中的最大值

題目描述 給定一個數組和滑動窗口的大小&#xff0c;找出所有滑動窗口里數值的最大值。例如&#xff0c;如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3&#xff0c;那么一共存在6個滑動窗口&#xff0c;他們的最大值分別為{4,4,6,6,6,5}&#xff1b; 針對數組{2,3,4,2,6,2,…

android 文字反轉_多文字共享信息系統

歐陽貴林 www.HeZi.net首發表于2016年03月23日“ 處在信息時代的開端&#xff0c;信息技術不應有特殊的文字性&#xff0c;需要創建多文字共享信息系統&#xff0c;給各國文字一個公平的參與信息與科技創新發展的平臺。這是世界的事&#xff0c;更是中國事。”01人類語言語言文…

LeetCode【1--兩數之和】 LeetCode【2--兩數相加】

兩數之和 題目描述 給定一個整數數組 nums 和一個目標值 target&#xff0c;請你在該數組中找出和為目標值的那 兩個 整數&#xff0c;并返回他們的數組下標。 你可以假設每種輸入只會對應一個答案。但是&#xff0c;你不能重復利用這個數組中同樣的元素。 解題思路 直接兩…

input數字開頭不能為0_李商隱為初戀寫詩,每句以數字開頭,最后10字一直被仿從未被超越...

上學時&#xff0c;每次寫作文&#xff0c;老師總愛在耳邊念叨&#xff1a;“你的作文得讓閱卷老師看得懂&#xff0c;不然不可能給你高分的&#xff01;”每次聽到話&#xff0c;筆者總是用李商隱的詩來和他斗嘴。是的&#xff0c;李商隱的詩作常常是讓人讀不懂的&#xff0c;…

lsass.exe 當試圖更新密碼時_“驅動人生”下載器木馬再度更新-你應該注意什么?...

360安全大腦監測到通過"驅動人生"供應鏈攻擊傳播的挖礦木馬在1月30日下午4時左右再次更新。此次更新中&#xff0c;木馬在此前抓取系統帳戶密碼的基礎上增加了抓取密碼hash值的功能&#xff0c;并試圖通過pass the hash攻擊進行橫向滲透&#xff0c;使得該木馬的傳播…

LeetCode【3--無重復的最長字串】 LeetCode【4--有序數組中的中位數】

無重復的最長字串 題目描述 給定一個字符串&#xff0c;請你找出其中不含有重復字符的 最長子串 的長度。 解題思路 看到這道題&#xff0c;其實就兩個步驟&#xff0c;遍歷字符串&#xff0c;記錄當前字符有沒有重復。 重復一般解決就是哈希&#xff0c;這里用個數組表示…

hwt字體轉換ttf_五分鐘教你弄懂了字體反爬是個啥

今天的文章內容主要是關于字體反爬。目前已知的幾個字體反爬的網站是貓眼&#xff0c;汽車之家&#xff0c;天眼查&#xff0c;起點中文網等等。以前也看過這方面的文章&#xff0c;今天跟個老哥在交流的時候&#xff0c;終于實操了一把&#xff0c;弄懂了字體反爬是個啥玩意。…

LeetCode【5--最長的回文子串】 LeetCode【6--Z字形變換】

最長的回文子串 題目描述 給定一個字符串 s&#xff0c;找到 s 中最長的回文子串。你可以假設 s 的最大長度為 1000。 解題思路 可以跟無重復的最長子串一樣&#xff0c;用一個滑動窗口&#xff0c;只不過這個窗口的右邊界往右&#xff0c;左邊界每回要從右邊界的下標往左…

androidstudio 日歷視圖怎么顯示農歷_中秋國慶旅游攻略怎么做?用這個便簽軟件很簡單...

九月已經到來&#xff0c;中秋節和國慶節距離我們也不遠了&#xff0c;今年的中秋和國慶節重疊了有足足八天的假期。不少人都想趁著這個小長假出門旅游&#xff0c;要想保證旅游質量&#xff0c;那么就要做好攻略。中秋國慶旅游攻略怎么做&#xff1f;要想做好一份中秋國慶旅游…

c++ select函數_PySpark 操作函數一覽

PySpark 操作函數一覽Created: Sep 14, 2020 10:28 AM Tags: Big Data, PySpark, Python, SparkPyspark.sql.functionsfrom pyspark.sql import functions as F函數使用說明基本數學函數類abssin、cos、tan、asin、acos 、atan、sinh、cosh、tanhceil、round、floorexp、log、l…

LeetCode【7--整數反轉】 LeetCode【8--字符串轉整數】

整數反轉 題目描述 給出一個 32 位的有符號整數&#xff0c;你需要將這個整數中每位上的數字進行反轉。 解題思路 x%10 取一位&#xff0c;x/10下一位&#xff0c;注意越界&#xff0c; 代碼實現 class Solution { public:int reverse(int x) {int sum 0;while(x){if(s…

word2003如何設置護眼模式_ERP系統上線,如何設置采購收貨的模式,提升企業的采購效率...

如何合理的規劃采購計劃上次去拜訪一個朋友&#xff0c;他們說公司既然出現沒有下達采購訂單&#xff0c;供應商也有送貨過來的事情&#xff0c;對于公司來說&#xff0c;這個是非常嚴重的問題。若用了ERP系統之后&#xff0c;如何避免類似的事情發生&#xff0c;今天我們來分享…