explicit Trade(vecstr_t&& vec) : _vec(vec)
{}
In the constructor above, even though vec
is of type rvalue reference to vecstr_t
, it is itself an lvalue. The basic rule to remember is - if it has a name, it's an lvalue.
There are very few contexts where an lvalue may automatically be moved from (such as the return statement of a function that returns an object by value), but a constructor's mem-initializer list is not one of them.
In your example, _vec
is copy constructed from vec
. If you want it to be move constructed instead, use std::move
.
explicit Trade(vecstr_t&& vec) : _vec(std::move(vec))
{}
Now the second call to print
will not print anything. Note that technically the second call could print a non-zero size because the contents of a moved from vector
are unspecified. But on most (probably all) implementations, you'll see an empty vector
.
Live demo
Your comment below says your intent is to accept both rvalues and lvalues, move only in the case of the former, and copy the argument otherwise. As currently written, your constructor will only accept rvalues, and not lvalues. There are a few different options to achieve what you want.
The easiest probably is to change the parameter so that it's taking the argument by value, and then unconditionally move.
explicit Trade(vecstr_t vec) : _vec(std::move(vec))
{}
The drawback with this approach is that you may incur an additional move construction of the vector
, but move constructing a vector
is cheap, and you should go with this option in most cases.
The second option is to create two overloads of the constructor
explicit Trade(vecstr_t&& vec) : _vec(std::move(vec)) {}
explicit Trade(vecstr_t const& vec) : _vec(vec) {}
The drawback with this one is that the number of overloads will increase exponentially as the number of constructor arguments increases.
The third option is to use perfect forwarding.
template<typename V>
explicit Trade(V&& vec) : _vec(std::forward<V>(vec)) {}
The code above will preserve the value category of the argument passed to the constructor when it forwards it to construct _vec
. This means that if vec
is an rvalue, the vecstr_t
move constructor will be called. And if it is an lvalue, it will be copied from.
The drawback with this solution is that your constructor will accept any type of argument, not just a vecstr_t
, and then the move/copy construction in the mem-initializer list will fail if the argument is not convertible to vecstr_t
. This may result in error messages that are confusing to the user.
As skypjack correctly comments, accessing an object through its name always results in an lvalue reference.
This is a safety feature and if you think it through you will realise that you are glad of it.
As you know, std::move
simply casts an l-value reference to an r-value reference. If we use the returned r-value reference immediately (i.e. un-named) then it remains an r-value reference.
This means that the use of the r-value can only be at the point in the code where move(x)
is mentioned. From a code-reader's perspective, it's now easy to see where x's state became undefined.
so:
1: auto x = make_x();
2: auto&& r = std::move(x);
3: // lots of other stuff
35: // ...
54: // ...
55: take_my_x(r);
does not work. If it did, someone maintaining the code would have a hard time seeing (and remembering) that x (defined on line 1) enters an undefined state on line 55 through a reference taken on line 2.
This is a good deal more explicit:
1: auto x = make_x();
2: //
3: // lots of other stuff
35: // ...
54: // ...
55: take_my_x(std::move(x));
Best Answer
std::move
only casts to Rvalue reference.foo
takes Rvalue ref tovector<int>
. Bymove(vecNumbers)
you getvector<int>&&
. Insidefoo
you just accessvecNumbers
which is defined inmain
. You didn't do any action which changed the content of this vector.If you really want to move (steal) content of
vecNumbers
you have to call either move constructor or move assignment operator. Insidefoo
you could do this in this way:or you can change signature of foo to be:
then when you call
move constructor of
vector<T>
is called which movesvecNumbers
tovalue
insidefoo
.