What would be the correct way to implement a move constructor considering the following class:
class C {
public:
C();
C(C&& c);
private:
std::string string;
}
Of course, the idea is to avoid copying string
or deallocating it twice.
Lets assume the basic example is just for clarity and I do need a move constructor.
I tried:
C::C(C&& c) {
//move ctor
string = std::move(c.string);
}
And
C::C(C&& c) : string(std::move(c.string)) {
//move ctor
}
Both compile fine on gcc 4.8 and run fine. It seems option A is the correct behaviour, string
gets copied instead of moved with option B.
Is this the correct implementation of a move constructor?
Both Constructors should work. So both are correct move constructors. The second one might be more efficient, since the first one default constructs
string
only to assign to it, while the second will simply move construct it and should therefore be more efficient. If the second one is less efficient I would suspect a compiler bug (remember that C++11 support is still not complete for current compilers) or a flawed test methology (how exactly do you test copy vs move and are you sure the move constructor not the assignment op is called in both cases?).Of course whenever possibly you could simply let the compiler generate your constructor via
C(C&&) = default;
.There is no need to implement a move constructor here since you don't have to manually manage memory. Move constructors are only useful when you manually use dynamic arrays in your class.
You can still explicitly have the compiler create the default move constructor even though it should have already been done even if you don't request it:
Since
std::string
itself has a move-ctor, the implicitly defined move-ctor forC
will take care of the proper move operation. You may not define it yourself. However, if you have any other data member and specifically:you may want to implement your own move-ctor.
In case you need the move-ctor, prefer the initializer list syntax. Always! Otherwise, you may end up with a default construction per object not mentioned in the initializer list (which is what you're forced for member objects with non-default ctors only).
Both your variants will move the string. The second variant should be preferred because it will not default construct an empty string just to move assign it afterwards.
Check your testcase and then your compiler's bugzilla list. You need to trace calls to both
string::operator=(string&&)
(1st case) andstring::string(string&&)
(2nd case) if you want to ensure for both cases that they move.