如何从C ++中的rvalue和lvalue参数中移出?

时间:2016-01-08 15:33:51

标签: c++ reference move lvalue rvalue

使用默认和移动构造函数的类Widget,我想编写一个函数:

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

    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)。 / p>

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

    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 个答案:

答案 0 :(得分:4)

  1. 是的,他们都是正确的,并保证只会调用移动。

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

  3. 如果您想要开心,可以创建自己的非模板&#34;移动Widget参考:&#34;

    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超过其初始化的右值的生命周期。