【问题标题】:How to move from both rvalue and lvalue arguments in C++?如何从 C++ 中的右值和左值参数移动?
【发布时间】:2016-01-08 15:33:51
【问题描述】:

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

  1. 接受 Widget 类型的左值和右值作为参数,
  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-slides,第 48 页]。但是,这种方法的缺点是它需要Widget 的复制构造函数,以防传递左值参数w(至少在g++ 4.9.2 中)。

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

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. 对于这个问题,还有其他可能更好的解决方案吗?

【问题讨论】:

    标签: c++ reference move lvalue rvalue


    【解决方案1】:
    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 的生命周期不会超过它可能已初始化的右值的生命周期。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-16
      • 2016-01-11
      • 1970-01-01
      • 2013-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多