Reputation: 163
Ok
So I have a class, MyClass. I would like to construct this class with say a vector of ints. I want to move this vector into the object. The class is not templated.
class Myclass {
public:
Myclass (std::vector<int> && in) : vec{in} {};
Myclass (std::vector<int> & in) : vec{in} {};
private:
std::vector<int> vec;
}
In my main I have
std::vector<int> orig (100);
Myclass A {orig};
std::cout << A.size() << '\n';
I want "orig" to be empty after moving it into "A". That does not happen in either of the options above. Even if I do
std::vector<int> orig (100);
Myclass A {std::move(orig)};
std::cout << A.size() << '\n'; // still prints 100
It looks like I can achieve it via
Myclass (std::vector<int> && in) : vec{std::move(in)} {}; // (1)
OR
Myclass (std::vector<int> & in) : vec{std::move(in)} {}; // (2)
OR
Myclass (std::vector<int> && in) : vec{std::forward<std::vector<int>(in)} {}; // (3)
My question is why does (1) appear to behave exactly like (2)?
Upvotes: 1
Views: 1257
Reputation: 180720
The thing to remember about references, rvalue and lvalue, is that they are lvalues. That means if you have a reference to a thing, that reference is an lvalue and you need std::move
to cast it to an rvalue so it can be moved.
The real difference between Myclass (std::vector<int> && in)
and Myclass (std::vector<int> & in)
is that with the first you have to use
Myclass A {std::move(orig)};
// or
Myclass A {std::vector(100)};
and cant pass an lvalue to it, where as with second you can only uses
Myclass A {orig};
as it wont let you pass an rvalue to it.
Also note that constructor 3 is "incorrect". You should only use std::forward
when you have a forwarding reference. std::vector<int> && in
is a rvalue reference, not a forwarding one so you should use std::move
instead. To use forward correctly you'd need a template constructor like
template <typename T, std::enable_if_t<
std::is_same<std::decay_t<T>,
std::vector<int>>, bool> = true>
Myclass (T&& in) : vec{std::forward<T>(in)} {};
Upvotes: 2