我有一个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));
}
答案 0 :(得分:7)
是的,参数的右值参考仅用于从调用者的角度选择函数,它的行为类似于函数内的左值引用。
原因是你只允许移动一次值,并且认为自动保持参数的rvalue-ness被认为太危险了。参数类型表示此函数接受rvalue,并通过提供实际移动值的实现来潜在地使用它。通过重载这个版本的方法可以用于支持非移动版本。或者它只是说函数需要一个右值。
在函数的实现中发生的事情是另一回事。考虑像
这样的方法void add_shape_twice(unique_ptr<Shape>&& shape)
{
m_shapes.push_back(shape);
m_shapes.push_back(shape);
}
如果shape
作为参数仍然是右值参考:您可能会意外地将值移动两次。因为在现实世界中,函数可能更长,并且多次引用参数(显式地或在循环或包扩展中)是很常见的,所以错误的可能性将是巨大的。
即使我们都知道它并且永远不会忘记它,它也意味着我们需要抛弃rvalue-ness,这会使代码非常笨拙。我们会不断添加并删除 rvalue-ness。
答案 1 :(得分:4)
是的,在进入rvalue引用现在具有名称的功能后,将其视为左值。因此你必须move
。
void add_shape(unique_ptr<Shape>&& shape)
^^^^^
或按值传递:
void add_shape(unique_ptr<Shape> shape)