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

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

本文关键字:值参 移动 参数 C++      更新时间:2023-10-16

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

  1. 接受类型为CCD_ 2的左值和右值两者作为自变量
  2. 内部"移动"从此参数,例如,到某个其他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)));
}

这种传递值方法显示了Andrei Alexandrescu在其scopeGuard()函数[ErrorHandling幻灯片,第48页]中的表现。然而,这种方法的缺点是,在传递左值参数w(至少对于g++4.9.2)的情况下,它需要Widget的复制构造函数

我能够找到以下解决方案来防止调用/需要复制构造函数。第一个使用左值和右值引用:

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. 这是相当主观的。我个人更喜欢转发参考,因为我讨厌代码重复。但是,它确实需要将代码放入标头中。

  3. 如果你想变得花哨,你可以创建自己的非模板"可移动Widget参考:"

    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的寿命不会超过其可能初始化的右值的寿命。