5

我有一个 View 和一个 Shape 类,其中 View “拥有”它的 Shape 对象。我将其实现为 unique_ptr 的向量。在函数 View::add_shape(std::unique_ptr&& shape) 中,我仍然需要在右值参数上使用 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));
}
4

2 回答 2

7

是的,来自参数的右值引用仅用于从调用者的角度选择函数,它的行为类似于函数内部的左值引用。

原因是您只能移动一次值,并且自动保持参数的右值性被认为太危险了。参数类型表明此函数接受一个右值,并通过提供一个实际移动该值的实现来潜在地使用它。通过重载这个版本的方法,可以使用有利于非移动版本的方法。或者它只是说该函数需要一个右值。

在函数的实现中发生了什么是另一回事。考虑一个类似的方法

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

如果shape作为参数仍然是右值引用:您会不小心将值移动了两次。由于在现实世界中函数可能更长,并且多次引用参数是很常见的(显式地或在循环或包扩展中),错误的可能性将是巨大的。

即使我们都知道它并且永远不会忘记它,这也意味着我们需要抛弃右值性,这会使代码变得非常笨拙。我们会不断地添加和删除右值。

于 2013-09-28T07:14:57.220 回答
4

是的,进入函数后,右值引用现在有了名字,所以它被视为左值。因此你必须这样move做。

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

或按值传递:

void add_shape(unique_ptr<Shape> shape)
于 2013-09-28T09:12:12.800 回答