2014-01-23 75 views
14

比方說,我得到了一個Foo類,其中包含一個std::vector類,它構造自std::unique_ptr另一個類的對象,Bar爲什麼這需要一個明確的std :: move?

typedef std::unique_ptr<Bar> UniqueBar; 

class Foo { 
    std::vector<UniqueBar> bars; 
public: 
    void AddBar(UniqueBar&& bar); 
}; 

void Foo::AddBar(UniqueBar&& bar) { 
    bars.push_back(bar); 
} 

這一個結果(以g ++ 4.8.1)編譯錯誤說的std::unique_ptr的拷貝構造被刪除,這是合理的。這裏的問題是,由於bar參數已經是右值引用,爲什麼調用std::unique_ptr的拷貝構造函數而不是其移動構造函數?

如果我明確地調用std::moveFoo::AddBar那麼編譯問題就會消失,但我不明白爲什麼需要這樣做。我認爲這是相當多餘的。

那麼,我錯過了什麼?

回答

16

基本上,每個有名字的對象都是一個左值。當使用右值引用將對象傳遞給函數時,該函數實際上會看到一個左值:它被命名。然而,右值參考所表明的是它來自一個準備好被轉移的對象。

換句話說,右值引用assymmetrical:

  • 他們只能接受右值,即,無論是臨時對象,對象即將消失,或物體看起來好像他們是右值(例如,結果的std::move(o))然而
  • 右值參考本身看起來,像一個左值
8

bar實際上是一個左值,因此您需要將它傳遞給std::move,以便在調用push_back時將其視爲右值。

Foo::AddBar(UniqueBar&& bar)過載只是確保當通過調用Foo::AddBar傳入一個右值時,過載被選中。但bar論點本身有一個名稱,是一個左值。

+0

此外,'的unique_ptr(常量的unique_ptr&)'被刪除。 – xis

9

混淆,因爲它看起來,一個右值參考結合於右值,但用作表達是左值

3

bar定義爲右值參考,但其值類別是一個左值。這是因爲對象有一個名字。如果它有一個名字,那是一個左值。因此,明確的std::move是必要的,因爲其意圖是擺脫名稱並返回一個xvalue(eXpiring-rvalue)。