2013-09-28 90 views
5

我有一個View和Shape類,其中View擁有它的Shape對象。 我正在實施這個作爲unique_ptr的矢量。 在函數View :: add_shape(std :: unique_ptr & & shape)中,我仍然需要在rvalue參數上使用std :: move來編譯它。爲什麼? (使用GCC 4.8)是作爲左值函數傳遞的參數作爲左值傳遞?

#include <memory> 
#include <vector> 
using namespace std; 

class Shape { }; 
class View 
{ 
    vector<unique_ptr<Shape>> m_shapes; 
    public: 
    void add_shape(unique_ptr<Shape>&& shape) 
    { 
    m_shapes.push_back(std::move(shape));// won't compile without the std::move 
    } 
}; 


int main() 
{ 
    unique_ptr<Shape> ups(new Shape); 
    View v; 
    v.add_shape(std::move(ups)); 
} 

回答

5

,從參數的右值參考僅用於選擇從調用方的角度的函數,它的行爲就像在函數內部左值參考。

原因是您只允許移動一次數值,並且認爲這太危險了,無法自動保持參數的右值。參數類型指示此函數接受右值並通過提供實際移動該值的實現來潛在地使用此值。通過重載這個版本的方法可以用來支持非移動版本。或者它只是說,函數需要一個右值。

在函數的實現中發生的是另一回事。考慮像

void add_shape_twice(unique_ptr<Shape>&& shape) 
{ 
    m_shapes.push_back(shape); 
    m_shapes.push_back(shape); 
} 

的方法,如果shape作爲參數將保持右值參考:你可能會不小心移動值的兩倍。由於在現實世界中,函數可能更長,並且多次引用參數(顯式地或在循環或包擴展中)是相當常見的,所以錯誤的可能性將是巨大的。

即使我們都會意識到它,並且永遠不會忘記它,這也意味着我們需要拋棄rvalue-ness,這會使代碼變得笨拙。我們會不斷地加入並刪除 rvalue-ness。

+0

謝謝。這回答了這個問題。雖然我認爲我會使用MM的建議傳遞值 – user1057165

+0

「它的行爲就像一個const函數中的左值引用」它不應該表現得像一個**非const **左值,以便它可以從? – neuront

+0

@neuront是的,謝謝你指出。現在已經修復,還有一些錯別字。 :) –

3

是的,在進入右值引用有現在名稱的函數後,所以它被視爲左值。因此你必須要move吧。

void add_shape(unique_ptr<Shape>&& shape) 
            ^^^^^ 

或者按值傳遞:

void add_shape(unique_ptr<Shape> shape) 
+0

我試過你的價值傳遞的建議,你是對的。它起作用,只要調用者仍然在unique_ptr上使用std :: move(因爲傳遞值涉及副本,而unique_ptr沒有副本ctr)。現在這一切都是有道理的 - 通過強制調用者在唯一的ptr上使用std :: move,顯然所有權正在被轉移。 – user1057165

+0

作爲後續,這是否意味着通過引用傳遞unique_ptr是一個壞主意?因爲這不需要調用者使用顯式的std :: move,但函數仍然可以移動指針。 – user1057165

+0

不,這不是個壞主意,但通過價值只是更短,更不容易出錯。 – deepmax