Having a class Widget
with default and move constructors, I'd like to write a function that:
Widget
as an argument,Widget
instance.For example:
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
where pointer_from_lrvalue()
might look like:
std::unique_ptr<Widget> pointer_from_lrvalue(Widget w) {
return std::unique_ptr<Widget>(new Widget(std::move(w)));
}
Such a passing-by-value approach shows Andrei Alexandrescu in his scopeGuard()
function [ErrorHandling-slides, page 48]. However, the drawback of this approach is that it requires a copy constructor of Widget
in case of passing an lvalue argument w
(at least with g++ 4.9.2).
I was able to find the following solutions to prevent calling/requiring a copy constructor. The first one uses lvalue and rvalue references:
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)));
}
The second one uses a universal reference:
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)));
}
I wonder:
Widget
copy constructor?Yes, they're both correct and guaranteed to only invoke moves.
This is rather subjective. I would personally prefer the forwarding reference, because I hate code duplication. However, it does require putting the code in a header.
If you want to go fancy, you can create your own 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()));
}
Care must be taken to ensure that no WidgetMover
lives beyond the lifetime of an rvalue it might have been initialised with.