程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 右值引用之移動語義,右值引用語義

右值引用之移動語義,右值引用語義

編輯:C++入門知識

右值引用之移動語義,右值引用語義


本文翻譯自關於右值引用解釋的經典文章,如果英文還可以的話,直接去看英文原文。thbecker.net/articles/rvalue_references/section_01.html

右值引用是c++中的一個特性,並且已經入駐c++11標准,可能大家一開始接觸的時候感覺有點難以理解,但是他的確是很好用的一個玩意兒。

右值引用解決了兩個問題:

1.move語義 2.完美轉發。

我們接下來先簡單介紹一下move語義,但是介紹move語義之前,我們需要先介紹左值和右值的含義。

在C語言中,我們給出左值的定義為:左值是一個表達式e,那麼他既可以出現在賦值操作符的左邊,也可以出現在右邊。右值是:只允許出現在賦值操作符右邊的表達式。

int a = 42;
int b = 43;

// a b 都是左值
a = b; // ok
b = a; // ok
a = a * b; // ok

// a * b 是右值
int c = a * b; // ok, 右值出現在=右邊
a * b = 42; // error, 右值不允許出現在=左邊

 那麼在c++中,左右值的定義也差不多,但是有一點點變化。在c++中,左值是:你可以對它取地址(&)操作的表達式,右值是非左值的表達式。

 // 左值:
  //
  int i = 42;
  i = 43; // ok, i 是左值
  int* p = &i; // ok, i 是左值
  int& foo();
  foo() = 42; // ok, foo() 是左值
  int* p1 = &foo(); // ok, foo() 是左值

  // 右值:
  //
  int foobar();
  int j = 0;
  j = foobar(); // ok, foobar() 是右值
  int* p2 = &foobar(); // error, 不能取右值表達式的地址
  j = 42; // ok, 42 是右值

 

假設我們有一個類X,他有一個成員函數為一個指針,可能指向某些資源之類的。那麼相應的構造、析構、拷貝等操作都是需要一些特殊的處理工作。

比如我們常見的std::vector,那麼X的拷貝操作就類似下面這樣:

X& X::operator=(X const & rhs)
{
  // [...]
  // 先收回資源m_pResource
  // 對rhs的m_pResource指向的資源做拷貝操作
  // 然後令m_pResource指向新的內存位置.
  // [...]
}

或者你可能會遇到下面這種代碼:

X foo();
X x;
x = foo();

那麼第三句,也就是最後一句要執行三個操作:

1.釋放原來x的資源。

2.克隆foo返回值中的資源給x的資源。

3.銷毀釋放返回值中的資源。

很顯然,這是很低效的做法,更聰明的做法是swap操作,交換x和返回值x`的資源,然後原x的資源會被自動釋放。

換句話說我們想做的就是:

...
swap(m_pResource,rhs.m_pResource);
...

這個就叫做move語義,在c++11中,通過重載可實現這個特性:

X& X::operator=(<???> rhs)
{
  // [...]
  // swap(m_pResource,rhs.m_pResource);
  // [...]  
}

 那麼這個???是個什麼類型呢?當然首先它應該是一種引用類型,減少不必要的值拷貝,然後我們還想它和傳統的引用類型分開,因為我們希望當右操作數為右值的時候,調用???這個重載,而當右操作數為左值的時候,調用原始的引用賦值構造,那麼好吧,那我們就把???叫做“右值引用”好了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved