以下內(nèi)容引自[wikipedia](https://zh.wikipedia.org/wiki)
### 什么是右值?
在C++11提出右值引用之前寇壳,C++03及更早的C++標(biāo)準(zhǔn)中厅贪,表達(dá)式的“值分類”(value categories)屬性為左值或右值。
左值是對(duì)應(yīng)(refer to)內(nèi)存中有確定存儲(chǔ)地址的對(duì)象的表達(dá)式的值,而右值是所有不是左值的表達(dá)式的值。因而,右值可以是字面量辈赋、臨時(shí)對(duì)象等表達(dá)式。能否被賦值不是區(qū)分C++左值與右值的依據(jù)膏燕。
---
C++的const左值是不可賦值的钥屈;而作為臨時(shí)對(duì)象的右值可能允許被賦值。左值與右值的根本區(qū)別在于是否允許取地址&運(yùn)算符獲得對(duì)應(yīng)的內(nèi)存地址坝辫。
---
### 什么是右值引用?
作為一種追求執(zhí)行效率的語言篷就,C++在用臨時(shí)對(duì)象或函數(shù)返回值給左值對(duì)象賦值時(shí)的深度拷貝(deep copy)一直受到詬病〗Γ考慮到臨時(shí)對(duì)象的生命期僅在表達(dá)式中持續(xù)竭业,如果把臨時(shí)對(duì)象的內(nèi)容直接移動(dòng)(move)給被賦值的左值對(duì)象,效率改善將是顯著的及舍。這就是移動(dòng)語義的來源未辆。
與傳統(tǒng)的拷貝賦值運(yùn)算符(copy assignment)成員函數(shù)、拷貝構(gòu)造(copy ctor)成員函數(shù)對(duì)應(yīng)锯玛,移動(dòng)語義需要有移動(dòng)賦值(move assignment)成員函數(shù)鼎姐、移動(dòng)構(gòu)造(move ctor)成員函數(shù)的實(shí)現(xiàn)機(jī)制「瘢可以通過函數(shù)重載來確定是調(diào)用拷貝語義還是移動(dòng)語義的實(shí)現(xiàn)。
右值引用就是為了實(shí)現(xiàn)移動(dòng)語義與完美轉(zhuǎn)發(fā)所需要而設(shè)計(jì)出來的新的數(shù)據(jù)類型饭尝。右值引用的實(shí)例對(duì)應(yīng)于臨時(shí)對(duì)象肯腕;右值引用并區(qū)別于左值引用,用作形參時(shí)能重載辨識(shí)(overload resolution)是調(diào)用拷貝語義還是移動(dòng)語義的函數(shù)钥平。
### std::forward
std::forward用途是:如果函數(shù)forward的實(shí)參的數(shù)據(jù)類型是左值引用实撒,則返回類型為左值引用姊途;如果函數(shù)forward的實(shí)參的數(shù)據(jù)類型是右值引用,則返回類型為右值引用知态,返回值的分類屬于臨終值(臨終值對(duì)象既有存儲(chǔ)地址因此可以綁定到右值引用變量上捷兰,而且它又是一個(gè)即將停止使用的對(duì)象可以被移走內(nèi)容),從而把參數(shù)的信息完整地傳遞給下一級(jí)被調(diào)用的函數(shù)负敏。
從上述std::forward的定義實(shí)現(xiàn)來看贡茅,實(shí)參必須是個(gè)為左值的引用對(duì)象,但是實(shí)參的數(shù)據(jù)類型有兩種可能:
> + 實(shí)參的數(shù)據(jù)類型T是左值引用類型其做,std::forward的返回類型T&&根據(jù)引用塌縮規(guī)則變?yōu)門&顶考,即返回值仍為左值引用類型;
> + 實(shí)參的數(shù)據(jù)類型T是右值引用類型(這是因?yàn)橛抑狄妙愋偷木呙兞繉?shí)際上表現(xiàn)為左值)妖泄,std::forward的返回類型S&&根據(jù)引用塌縮規(guī)則變?yōu)镾&&驹沿,即返回值為右值引用類型。
### std::move
std::move是個(gè)模板函數(shù)蹈胡,把輸入的左值或右值轉(zhuǎn)換為右值引用類型的臨終值渊季。其核心是強(qiáng)制類型轉(zhuǎn)換static_cast()語句。
### 示例測試
代碼:
```
#include
#include
#include
#include
class Test{
private:
std::string _name;
public:
Test(const char* name):_name(name) {
std::cout << std::string("constructor ") + std::string(_name) << std::endl;
}
~Test() {
std::cout << std::string("destructor ") + std::string(_name) << std::endl;
}
std::string& print() {
return _name;
}
};
int main(int argc, const char** argv) {
std::cout << "teset begin" << std::endl;
std::cout<
auto testA = std::make_shared("test a");
auto testB = std::make_shared("test b");
auto testC = std::make_shared("test c");
{
std::vector> list;
list.push_back(testA);
// 無條件轉(zhuǎn)換成右值引用
list.push_back(std::move(testB));
// forward 有條件轉(zhuǎn)換
list.push_back(std::forward>(testC));
list.push_back(std::forward>(std::make_shared("test d")));
list.push_back(std::forward&&>(std::make_shared("test e")));
}
std::cout<
std::cout << "list life end" << std::endl;
std::cout << "teset end" << std::endl;
std::cout<
return 0;
}
```
運(yùn)行輸出:
```
g++ test.cpp
./a.out
teset begin
constructor test a
constructor test b
constructor test c
constructor test d
destructor test b
destructor test c
destructor test d
list life end
teset end
destructor test a
```
從結(jié)果可以看出, 使用std::move或std::forward后, 對(duì)象轉(zhuǎn)移到容器內(nèi)部, 容器銷毀時(shí)對(duì)象跟著銷毀, 此時(shí)shared_ptr對(duì)象失效, 成為無效對(duì)象(nullptr).