2013-09-28 78 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