I have a simple class which contains an std::vector, and I would like to benefit from move semantics (not RVO) when returning the class by value.
I implemented the move constructor, copy constructor and copy assignment operators in the following way:
class A
{
public:
// MOVE-constructor.
A(A&& other) :
data(std::move(other.data))
{
}
// COPY-constructor.
A(const A& other) :
data(other.data)
{
}
// COPY-ASSIGNMENT operator.
A& operator= (const A& other);
{
if(this != &other)
{
data = other.data;
}
return *this;
}
private:
std::vector<int> data;
};
Are the above implementations correct?
And an other question: do I even have to implement any of these members, or are they auto-generated by the compiler? I know that the copy-constructor and the copy-assignment operator are generated by default, but can the compiler auto-generate the move constructor as well? (I compile this code both with MSVC and GCC.)
Thanks in advance for any suggestions. (I know that there already are some similar questions, but not for this exact scenario.)
The move constructor and move assignment operator are simple. Instead of deep copying the source object (a) into the implicit object, we simply move (steal) the source object's resources. This involves shallow copying the source pointer into the implicit object, then setting the source pointer to null.
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.
The move assignment operator is different than a move constructor because a move assignment operator is called on an existing object, while a move constructor is called on an object created by the operation. Thereafter, the other object's data is no longer valid.
The move constructor is correct 1 but the rest of the class isn’t, you are violating the rule of three: your class needs an appropriate copy constructor and copy assignment operator. Is there a better way to implement the move constructor? Why did you not directly copy the members, instead dereferencing rcOther.mpiSize?
So the following code ostensibly calls the move constructor: A f () { return A (); } A a = f (); // move construct (not copy construct) from the return value of f In fact move-elision might kick in, in which case only the no-args constructor is actually called.
Why doesn’t the compiler auto-generate a move constructor? The compiler does generate a move constructor if you don’t do so – after a fashion. However, the compiler cannot second-guess your motives so it doesn’t know what the pointer in your class does.
Trivial move constructor. A trivial move constructor is a constructor that performs the same action as the trivial copy constructor, that is, makes a copy of the object representation as if by std::memmove. All data types compatible with the C language (POD types) are trivially movable.
They're all unnecessary for this class[*], since it would have implicit ones if you didn't declare any of them.
Your constructors are fine. So the following code ostensibly calls the move constructor:
A f() { return A(); }
A a = f(); // move construct (not copy construct) from the return value of f
In fact move-elision might kick in, in which case only the no-args constructor is actually called. I assume you plan to provide some constructors other than copy and move ;-)
Your copy assignment is fine, it differs from the implicit one only in that it has the self-assignment check, which the implicit one would not. I don't think we should have the argument whether a self-assignment check is worth it or not, it's not incorrect.
You haven't defined a move-assignment operator. Given that you defined the others, you should have done, but if you get rid of the rest it's implicit[*]. The move assignment operator (whether user-defined or implicit) is what ensures that the following code will move instead of copying:
A a;
a = f();
[*] On a completed C++11 implementation, of which so far none exist. You can check on a per-compiler basis whether this feature is implemented yet, and probably you'll end up with some horrible #define
shenanigans until MSVC does.
For this exact scenario, You don't need to declare any move/copy/assignment functions. Compiler will generate correct defaults.
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