2016-09-08 53 views
2

在下面的代碼中,爲什麼不首先撥打mkme = mvme_rv發送到T& operator=(const T&&)爲什麼我必須調用右值引用?

#include <iostream> 
#include <string> 
#include <vector> 

using namespace std; 
using T = vector<int>; 

int main() 
{ 
    T mvme(10, 1), mkme; 
    T&& mvme_rv = move(mvme); // rvalue ref? 
    mkme = mvme_rv;   // calls T& operator=(const T&)? 
    cout << mvme.empty();  // 0 
    mkme = move(mvme_rv);  // calls T& operator=(const T&&)? 
    cout << mvme.empty();  // 1 
} 
+3

'mvme_rv'的類型是對'T'的右值引用,但是當通過名稱使用該變量時,它只不過是一個左值。 – skypjack

+2

區分「右值參考」和「右值」。 –

+1

命名錶達式總是lvlaues。術語「右值引用」中的「右值」一詞描述了*引用*的類型:右值引用是綁定到右值的引用,並且左值引用是綁定到左值(大部分)的引用。在這個意義上,右值引用是一種新的語言功能,它爲語言增加了一種通用的右值到左值的轉換,但迄今爲止還沒有這種轉換。 –

回答

-3

這行代碼:

mkme = mvme_rv; 

是副本,因此將使用複製分配(T& operator=(const T&))。關鍵在於這兩個對象可以在之後使用,並且應該 - 如果正確實施 - 提供兩個相同的對象。

相反,這行代碼:

mkme = move(mvme_rv); 

是移動分配(T& operator=(const T&&))。按照慣例,這會破壞mvme_rv對象(或至少清除它),並使mkme基本上是以前的mvme_rv

實際上T&&意味着一個臨時對象(又名xvalue) - 一些不會持續的東西。 std::move方法基本上將對象轉換爲臨時的(對於該措辭,信貸給@ richard-Hodges)。這可以在移動分配方法中使用。

所以最後回答你爲什麼不mkme = mvme_rv派遣T& operator=(const T&&)問題:這是因爲mvme_rv不是一個臨時對象(又名xavalue)。


進一步瞭解xvalues:http://en.cppreference.com/w/cpp/language/value_category

+0

「std :: move操作符基本上需要一個普通的對象並且撕掉內核」不,它不影響操作數。它不是一個運營商。 – juanchopanza

5

作爲skypjack正確地註釋,通過其名稱訪問對象總是導致左值參考。

這是一個安全功能,如果你認爲它會通過你會意識到你很高興它。

如您所知,std::move只是將一個l值引用轉換爲r值引用。如果我們立即使用返回的r值引用(即未命名),那麼它仍然是一個r值引用。

這意味着只能在提到move(x)的代碼中使用r值。從代碼閱讀器的角度來看,現在很容易看到x的狀態變得未定義。

這樣:

1: auto x = make_x(); 
2: auto&& r = std::move(x); 
3: // lots of other stuff 
35: // ... 
54: // ... 
55: take_my_x(r); 

不起作用。如果是這樣的話,維護代碼的人很難看到(並記住)x(定義在第1行上)通過第2行上的參考在行55上進入未定義狀態。

這是一個很好的交易更明確:

1: auto x = make_x(); 
2: // 
3: // lots of other stuff 
35: // ... 
54: // ... 
55: take_my_x(std::move(x)); 
相關問題