如何从 C++ 中的右值和左值参数移动?

How to move from both rvalue and lvalue arguments in C++?

有一个带有默认和移动构造函数的 class Widget,我想编写一个函数:

  1. 接受 类型 Widget 的左值和右值作为参数,
  2. 内部 'moves' 从这个论点,例如,到其他一些 Widget 实例。

例如:

Widget w;
auto p1 = pointer_from_lrvalue(Widget()); // rvalue argument
auto p2 = pointer_from_lrvalue(w); // lvalue argument
// w is guaranteed to be no longer used from now on

其中 pointer_from_lrvalue() 可能看起来像:

std::unique_ptr<Widget> pointer_from_lrvalue(Widget w) {
   return std::unique_ptr<Widget>(new Widget(std::move(w)));
}

这种 按值传递方法 在他的 scopeGuard() 函数 [ErrorHandling-slides,第 48 页中展示了 Andrei Alexandrescu。但是,这种方法的缺点是它 需要 Widget 的复制构造函数 以防传递左值参数 w (至少对于 g++ 4.9.2 ).

我找到了以下解决方案来防止 calling/requiring 复制构造函数。第一个使用左值和右值引用:

std::unique_ptr<Widget> pointer_from_lrvalue(Widget& w) {
   return std::unique_ptr<Widget>(new Widget(std::move(w)));
}    
std::unique_ptr<Widget> pointer_from_lrvalue(Widget&& w) {
   return std::unique_ptr<Widget>(new Widget(std::move(w)));
}    

第二个使用通用引用:

template <typename T>
std::unique_ptr<std::remove_reference_t<T>> pointer_from_lrvalue(T&& t) {
   return std::unique_ptr<std::remove_reference_t<T>>
       (new std::remove_reference_t<T>(std::move(t)));
}

我想知道:

  1. 这些解决方案是否正确并且保证不调用Widget复制构造函数?
  2. 我应该选择这两种解决方案中的哪一种?
  3. 是否有其他可能更好的解决方案来解决这个问题?
  1. 是的,它们都是正确的并且保证只调用移动。

  2. 这是相当主观的。我个人更喜欢转发参考,因为我讨厌代码重复。但是,它确实需要将代码放在 header.

  3. 如果你想花哨,你可以自己创造non-template"movable Widget reference:"

    class WidgetMover
    {
      Widget& widget;
    
    public:
      Widget&& moveWidget() { return std::move(widget); }
    
      WidgetMover(Widget &w) : widget(w) {}
      WidgetMover(Widget &&w) : widget(w) {}
    };
    
    std::unique_ptr<Widget> pointer_from_lrvalue(WidgetMover w) {
       return std::unique_ptr<Widget>(new Widget(w.moveWidget()));
    }
    

    必须注意确保没有 WidgetMover 存在于可能已初始化的右值的生命周期之外。