如何从 C++ 中的右值和左值参数移动?
How to move from both rvalue and lvalue arguments in C++?
有一个带有默认和移动构造函数的 class Widget
,我想编写一个函数:
- 接受 类型
Widget
的左值和右值作为参数,
- 内部 '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)));
}
我想知道:
- 这些解决方案是否正确并且保证不调用
Widget
复制构造函数?
- 我应该选择这两种解决方案中的哪一种?
- 是否有其他可能更好的解决方案来解决这个问题?
是的,它们都是正确的并且保证只调用移动。
这是相当主观的。我个人更喜欢转发参考,因为我讨厌代码重复。但是,它确实需要将代码放在 header.
中
如果你想花哨,你可以自己创造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
存在于可能已初始化的右值的生命周期之外。
有一个带有默认和移动构造函数的 class Widget
,我想编写一个函数:
- 接受 类型
Widget
的左值和右值作为参数, - 内部 '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)));
}
我想知道:
- 这些解决方案是否正确并且保证不调用
Widget
复制构造函数? - 我应该选择这两种解决方案中的哪一种?
- 是否有其他可能更好的解决方案来解决这个问题?
是的,它们都是正确的并且保证只调用移动。
这是相当主观的。我个人更喜欢转发参考,因为我讨厌代码重复。但是,它确实需要将代码放在 header.
中
如果你想花哨,你可以自己创造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
存在于可能已初始化的右值的生命周期之外。