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?
A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying.
If any constructor is being called, it means a new object is being created in memory. So, the only difference between a copy constructor and a move constructor is whether the source object that is passed to the constructor will have its member fields copied or moved into the new object.
A move constructor is executed only when you construct an object. A move assignment operator is executed on a previously constructed object. It is exactly the same scenario as in the copy case.
To correct this, remove the move constructor completely. In the case of the class, once a copy constructor is present (user defined), the move is implicitly not generated anyway (move constructor and move assignment operator).
Since std::string
itself has a move-ctor, the implicitly defined move-ctor for C
will take care of the proper move operation. You may not define it yourself. However, if you have any other data member and specifically:
12.8 Copying and moving class objects
12 An implicitly-declared copy/move constructor is an inline public member of its class. A defaulted copy- /move constructor for a class X is defined as deleted (8.4.3) if X has:
— a variant member with a non-trivial corresponding constructor and X is a union-like class,
— a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor, or
— a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor, or
— for the move constructor, a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.
13 A copy/move constructor for class X is trivial if it is neither user-provided nor deleted and if
— class X has no virtual functions (10.3) and no virtual base classes (10.1), and functions (10.3) and no virtual base classes (10.1), and
— the constructor selected to copy/move each direct base class subobject is trivial, and
— for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial; otherwise the copy/move constructor is non-trivial.
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).
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