C 11中的新特性右值引用

2022-09-08 13:12:14 字數 3633 閱讀 1956

右值引用 (rvalue referene) 是 c++ 新標準 (c++11, 11 代表 2011 年 ) 中引入的新特性 , 它實現了轉移語義 (move sementics) 和精確傳遞 (perfect forwarding)。它的主要目的有兩個方面: 

1. 消除兩個物件互動時不必要的物件拷貝,節省運算儲存資源,提高效率。 

2. 能夠更簡潔明確地定義泛型函式。

c++( 包括 c) 中所有的表示式和變數要麼是左值,要麼是右值。

左值是可以放在賦值號左邊可以被賦值的物件;左值必須要在記憶體中有實體;通俗的講左值的定義就是非臨時物件,可以被取位址的物件,那些可以在多條語句中使用的物件。 所有的變數都滿足這個定義,在多條**中都可以使用,都是左值。 

右值只能出現在賦值號右邊取出值賦給其他變數;右值可以在記憶體也可以在cpu暫存器右值是指臨時的物件,不可以被取位址,它們只在當前的語句中有效。

int i = 0;  // 在這條語句中,i 是左值,0 是臨時值,就是右值。
在c++11之前,右值是不能被引用的,如:

int &a = 1;   // error c2440: 「初始化」: 無法從「int」轉換為「int &」
我們最多只能用常量引用來繫結乙個右值,如:

const int &a = 1;
在c++11中,我們可以引用右值,使用&&來實現:

int &&a = 1;
有如下string類,實現了拷貝建構函式和賦值運算子過載。

class mystring 

public:

mystring()

mystring(const char* p)

mystring(const mystring& str)

mystring& operator=(const mystring& str)

std::cout << "copy assignment is called! source: " << str._data << std::endl;

return *this;

}virtual ~mystring()

}};int main()

執行結果:

copy assignment is called! source: hello

destructor is called!

copy constructor is called! source: world

destructor is called!

destructor is called!

destructor is called!

總共執行了2次拷貝,mystring("hello")mystring("world")都是臨時物件,臨時物件被使用完之後會被立即析構,在析構函式中free掉申請的記憶體資源。

如果能夠直接使用臨時物件已經申請的資源,並在其析構函式中取消對資源的釋放,這樣既能節省資源,有能節省資源申請和釋放的時間。 這正是定義轉移語義的目的。

通過加入定義轉移建構函式轉移賦值操作符過載來實現右值引用(即復用臨時物件):

mystring(mystring&& str) 

mystring& operator=(mystring&& str)

return *this;

}

執行結果:

move assignment is called! source: hello

move constructor is called! source: world

destructor is called!

destructor is called!

需要注意的是:右值引用並不能阻止編譯器在臨時物件使用完之後將其釋放掉的事實,所以轉移建構函式轉移賦值操作符過載函式中都將_data賦值為了null,而且析構函式中保證了_data != null才會釋放。

既然編譯器只對右值引用才能呼叫轉移建構函式和轉移賦值函式,又因為所有命名物件都只能是左值引用。 在這樣的條件了,如果已知乙個命名物件不再被使用而想對它呼叫轉移建構函式和轉移賦值函式,也就是把乙個左值引用當做右值引用來使用,怎麼做呢?標準庫提供了函式 std::move,這個函式以非常簡單的方式將左值引用轉換為右值引用。

void processvalue(int& i)  

void processvalue(int&& i)

int main()

執行結果:

lvalue processed: 0 

rvalue processed: 0

std::move在提高 swap 函式的的效能上非常有幫助,一般來說,swap函式的通用定義如下:

template void swap(t& a, t& b) 

有了std::move,再結合右值引用,就可以避免不必要的拷貝了。 swap函式的定義變為 :

template void swap(t& a, t& b) 

可以使用第三節中的mystring類進行測試:

int main()
精確傳遞就是在引數傳遞過程中,所有這些屬性和引數值都不能改變。在泛型函式中,這樣的需求非常普遍。 舉例說明比較好理解。

forward_value函式只有乙個引數val,定義如下:

template void forward_value(const t& val)  

template void forward_value(t& val)

函式 forward_value 為每乙個引數必須過載兩種型別,t& 和 const t&,否則,下面四種不同型別引數的呼叫中就不能同時滿足:

int a = 0; 

const int &b = 1;

forward_value(a); // int&

forward_value(b); // const int&

forward_value(2); // int&

對於乙個引數就要過載兩次,也就是函式過載的次數和引數的個數是乙個正比的關係。這個函式的定義次數對於程式設計師來說,是非常低效的。我們看看右值引用如何幫助我們解決這個問題:

template void forward_value(t&& val)
只需要定義一次,接受乙個右值引用的引數,就能夠將所有的引數型別原封不動的傳遞給目標函式。

**:

C 11的新特性 右值引用

先看 include pch.h include include using namespace std template class myarray void pushback t data private int mcapacity int msize elemtype paddr templa...

C 11新特性 移動語義和右值引用

傳統的c 引用 左值引用 使得識別符號關聯到左值。左值是乙個表示資料的表示式 如變數名或解除引用的指標 程式可以獲得其位址。c 11新增了右值引用。右值引用,顧名思義,可以關聯到右值,即 可以出現在賦值表示式的右邊,但不能對其應用位址運算子的值。右值包括字面常量 c風格字串除外,它表示位址 諸如x ...

C 11 特性 左值 右值 右值引用 詳解

在c 11中所有的值必屬於左值 右值兩者之一,右值又可以細分為純右值 將亡值。在c 11中可以取位址的 有名字的就是左值,反之,不能取位址的 沒有名字的就是右值 將亡值或純右值 舉個例子,int a b c,a就是左值,其有變數名為a,通過 a可以獲取該變數的位址 表示式b c 函式int func...