北京企業(yè)網(wǎng)站開發(fā)費用有什么平臺可以推廣信息
文章目錄
- 前言
- 一、右值引用是什么?
- 那么,什么又是右值?
- 右值引用
- 二、使用步驟和意義
- 1.
- 1.1
- 1.2
- 2.右值引用的最大意義
- 2.1 完美轉(zhuǎn)發(fā)
- 2.2 萬能折疊
前言
C++11 是2011年對C++這門語言發(fā)布的新標準,并且此次標準引入了十分多的新特性,很大程度上優(yōu)化且增加了C++語言的實用性,本章主要講 C++11 新引用的右值引用。
一、右值引用是什么?
在從C語言進入到C++時,我們就已經(jīng)開始接觸到引用
int i = 0;
int& ir = i;
引用,在我們以往的理解就是給一個變量取別名,實際上我們也確實可以這么理解。
那么,什么又是右值?
這里就需要區(qū)分左值和右值的概念,這里就需要注意,許多剛接觸到C++的初學者,可能只是片面的認為 在"=“左邊的就是左值, 在”="右邊的就是右值,而這種區(qū)分方式是嚴重錯誤的。
int i = 0;
const int i1 = 2;
那我們可以理解為具有常性不可更改的就是右值,可更改的就是左值嗎? 也不行
其實區(qū)分左值還是右值很簡單,就看它是否可以被取地址,可以被取地址的就是左值,不可以被取地址的就是右值。
int i = 0; 左值
const char c; 左值
double* d; 左值
string str; 左值
int& ii = i; 左值
以上都可以被取地址,所以都是左值
1; 右值
sizeof(int); sizeof(int)的返回值為右值
(x+y); 運算符的本質(zhì)其實也是調(diào)用函數(shù)所以也是右值
int(1); 匿名對象也是右值
以上就是常見的右值
右值引用
左值引用 是 int& ii = i;
而C++新增加的右值引用是專門對于右值進行引用,使用&&
int a = 1, b = 2;
int&& i = 10;
int&& i1 = a+b;
int&& i2 = sizeof(a);
二、使用步驟和意義
1.
右值引用和左值引用其實都用共同的目的,那就是為了減少拷貝,在我們曾經(jīng)模擬實現(xiàn)的string和vector中,我們?yōu)榱藴p少拷貝,總是會去使用左值引用。
string代碼如下(示例):
void Swap(string& str)
{::swap(_str, str._str);::swap(_size, str._size);::swap(_capacity, str._capacity);
}
string(const string& str) //拷貝構(gòu)造:_str(nullptr), _capacity(0),_size(0)
{string tmp(str._str);Swap(tmp);
}
1.1
那么是不是左值引用就只能引用左值?
string(const string& str) //拷貝構(gòu)造:_str(nullptr), _capacity(0),_size(0)
{string tmp(str._str);Swap(tmp);
}string str = string("hello world");
這里我們采用匿名對象來構(gòu)造一個string,剛剛我們也說了,匿名對象也是右值,但是仍然可以走上面的拷貝構(gòu)造,因為我們使用了const string& str,加了"const"這就使得我們的左值引用也可以引用右值。
而我們的右值引用是不可以引用左值的,大家可以自行嘗試,編譯器是會報錯的。
1.2
綜上述,既然我們的const 左值引用也可以去引用右值,那么右值引用的意義是不是就不大了?
2.右值引用的最大意義
我們先來看剛剛的示例代碼
代碼如下(示例):
string(const string& str) //拷貝構(gòu)造:_str(nullptr), _capacity(0),_size(0)
{string tmp(str._str); //這里發(fā)生了拷貝Swap(tmp);
}
即使我們采用左值引用,這里仍然會發(fā)生一次拷貝,而在某些容器例如vector下,拷貝的代價可能會十分巨大,而面對一些將亡值,拷貝的意義并不大,因為有更好的方式! 這個時候,右值引用就凸顯出了它的作用!
string(string&& str):_str(nullptr), _capacity(0), _size(0){Swap(str);}
因為在這種情況下,這里的str一定是一個右值中的將亡值,它的生命周期僅僅只是為了構(gòu)造新的string,所以我們完全可以將其數(shù)據(jù)用過Swap掠奪過來,再讓他自行析構(gòu),這就減少了一次拷貝,提高了程序的運行效率!
2.1 完美轉(zhuǎn)發(fā)
關(guān)于右值引用還需要注意的是一旦使用了右值引用,那么就會改變其原有屬性
int a = 1, b = 2;
int&& i = 10;
int&& i1 = a+b;
int&& i2 = sizeof(a);
就例如該上 這里的i,i1,i2都會因為右值引用改變右值屬性,變?yōu)樽笾祵傩?#xff0c;并且你可以對它們的內(nèi)存數(shù)據(jù)進行修改,這是因為這些右值數(shù)據(jù)被移動到了一個其他區(qū)域儲存起來。
而C++11為了保持其原有的屬性,提供了完美轉(zhuǎn)發(fā)。
std::forward(x);
void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }
// std::forward<T>(t)在傳參的過程中保持了t的原生類型屬性。
template<typename T> //萬能折疊
void PerfectForward(T&& t)
{Fun(std::forward<T>(t));//完美轉(zhuǎn)發(fā)
}
2.2 萬能折疊
template<typename T> //萬能折疊
void PerfectForward(T&& t)
{Fun(std::forward<T>(t));
}
通過這樣的模版格式,來使得t做一個自動折疊的功能,如果傳的是一個左值,那么就是用左值引用,如果是一個右值,就是右值引用。