Seeing as C++11 supports move semantics, when initializing data members from arguments, should we attempt to move the value instead of copying it?
Here's an example showing how I would approach this in pre-C++11:
struct foo {
std::vector<int> data;
explicit foo(const std::vector<int>& data)
: data(data)
{
}
};
Here, the copy constructor would be called.
In C++11, should we get into the habit of writing like this:
struct foo {
std::vector<int> data;
explicit foo(std::vector<int> data)
: data(std::move(data))
{
}
};
Here, the move constructor would be called... as well as the copy constructor if the argument passed is an lvalue, but the benefit is that if an rvalue was passed, the move constructor would be called instead of the copy one.
I'm wondering if there's something I'm missing.
In C++11, the language has been extended to allow specifying an initializer in the declaration, but this is just a shorthand—the actual initialization still takes place at the top of the constructor. Initialization of data members will also still occur in order of declaration.
There are two ways to initialize a class object: Using a parenthesized expression list. The compiler calls the constructor of the class using this list as the constructor's argument list. Using a single initialization value and the = operator.
For the static variables, we have to initialize them after defining the class. To initialize we have to use the class name then scope resolution operator, then the variable name. Now we can assign some value. The following code will illustrate the of static member initializing technique.
My initial answer to your question was:
Don't copy data that you want to move. You can add a constructor using a rvalue reference, if performance is a problem:
explicit foo(std::vector<int>&& data)
: data(std::move(data)) // thanks to Kerrek SB
{
}
Not exactly matching your question, but reading Rule-of-Three becomes Rule-of-Five with C++11? seems to be useful.
Edit:
However, the accepted answer to Passing/Moving parameters of a constructor in C++0x seems to advocate your approach, especially with more than one parameter. Otherwise there would be a combinatorial explosion of variants.
Passing by value in the copy constructor only helps when the argument is movable, otherwise you could end up with up to two copies (one for the argument passing, one for the member construction). So I'd say it's better to write a copy and a move constructor separately.
Passing by value makes sense for the assignment operator if you have a properly implemented swap
function, though:
Foo & operator=(Foo other) { this->swap(std::move(other)); }
Now if other
is moveable, Foo
's move constructor comes in during argument construction, and if other
is merely copyable, then the one necessary copy is made during argument construction, but in both cases you get to use the moving version of swap
, which ought to be cheap. But this relies on the existence of a move constructor!
So note that out of "construction", "swap" and "assigment" you will have to implement two properly, and only the third can take advantage of the other two. Since swap
should be no-throw, using the swap trick in the assigment operator is basically the only option.
Yes, you are doing it correctly. Any time you need a copy of a value, do it in the parameters by passing by value.
The following is correct:
struct foo {
std::vector<int> data;
explicit foo(std::vector<int> data)
: data(std::move(data))
{
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With