Reputation: 1317
I have a question about using std::move
in C++.
Let's say I have the following class, which in its constructor takes a std::vector
as a parameter:
class A
{
public:
A(std::vector<char> v): v(v) {}
private:
std::vector<char> v;
};
But if I write the following somewhere:
std::vector<char> v;
A a(v);
the copy constructor of std::vector
will be called twice, right?
So should I write constructor for A
like the following?
class A
{
public:
A(std::vector<char> v): v(std::move(v)) {}
private:
std::vector<char> v;
};
And what if I would like to call the following?
std::vector<char> v;
A a(std::move(v));
Is that okay with the second version of the constructor, or should I create another constructor for A
that takes std::vector<char>&&
?
Upvotes: 6
Views: 12429
Reputation: 25593
You should write a move constructor!
A::A( std::vector<char>&& vec): v(std::move(vec) {}
If you did not write that, you get one more copy here.
You have to keep in mind that your vector will be moved "away". So if you write something like:
std::vector<char> v;
A a(std::move(v));
so your vector v should not used after the call of constructor of A. All elements are moved away and iterators to the content are invalid. The vector can be used to store new data.
So if you write
std::vector<char> v;
A a(v);
and this will result in a move like in your example, nobody would expect the move.
Upvotes: 2
Reputation: 29332
Make two constructors: The first constructor should be by const&, the second as rvalue&& so it can use move semantics:
class A
{
public:
A(const std::vector<char>& v_) : v(v_) { std::cout << "const& ctor\n"; }
A(std::vector<char>&& v_) : v(std::move(v_)) { std::cout << "rvalue&& ctor\n"; }
private:
std::vector<char> v;
};
Test:
int main()
{
std::vector<char> v1{ 'a', 'b', 'c', 'd' };
A a1(v1);
A a2(std::vector<char>{ 1, 2, 3, 4 });
return 0;
}
Output:
const& ctor
rvalue&& ctor
Upvotes: 5
Reputation: 170045
Your second scheme is fine.
The vector will just be moved twice with the second version (which moves the by-value parameter into your member). If you don't mind the cost of the extra move, you can stick with just moving the by-value parameter into your member.
If you do mind, then make two constructors for different value categories of the parameter.
Upvotes: 5
Reputation: 62553
Many times with vectors you would be fine by accepting vector
by value and moving from it. So,
A(std::vector<char> v): v(std::move(v)) {}
However, this assumes that you are only calling it for 'natural' lvalues or temporaries. Meaning, it would be performant for cases like
A a(std::vector<char>{....}); // <--- 1
std::vector<char> my_vec;
A b(my_vec); // <--- 2
If you expect to call it with an lvalue which you'd like to be moved from, like in your example, than you need two constructors - with const lvalue
reference and rvalue
references:
A(const std::vector<char>& v) : v(v) { }
A(std::vector<char>&& v) : v(std::move(v)) { }
Upvotes: 3