An example move constructor implementation from a C++ course I’m taking looks a bit like this:
/// Move constructor Motorcycle::Motorcycle(Motorcycle&& ori) : m_wheels(std::move(ori.m_wheels)), m_speed(ori.m_speed), m_direction(ori.m_direction) { ori.m_wheels = array<Wheel, 2>(); ori.m_speed = 0.0; ori.m_direction = 0.0; }
(m_wheels
is a member of type std::array<Wheel, 2>
, and Wheel only contains a double m_speed
and a bool m_rotating
. In the Motorcycle class, m_speed
and m_direction
are also double
s.)
I don’t quite understand why ori
’s values need to be cleared.
If a Motorcycle
had any pointer members we wanted to “steal”, then sure, we’d have to set ori.m_thingy = nullptr
so as to not, for example, delete m_thingy
twice. But does it matter when the fields contain the objects themselves?
I asked a friend about this, and they pointed me towards this page, which says:
Move constructors typically "steal" the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, I/O streams, running threads, etc), rather than make copies of them, and leave the argument in some valid but otherwise indeterminate state. For example, moving from a
std::string
or from astd::vector
may result in the argument being left empty. However, this behaviour should not be relied upon.
Who defines what indeterminate state means? I don’t see how setting the speed to 0.0
is any more indeterminate than leaving it be. And like the final sentence in the quote says — code shouldn’t rely on the state of the moved-from Motorcycle anyway, so why bother cleaning it up?
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.
A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying.
If you need to use mutable to properly implement copy/move constructors, than your design is wrong, invalid and very error-prone. That's why move constructors were introduced. They can give you huge performance boost absolutely free, without any need for dirty tricks.
The move assignment operator takes an r-value reference only e.g. CLASSA a1, a2, a3; a1 = a2 + a3; In the copy assignment operator , other can be constructor using a copy constructor or a move constructor (if other is initialized with an rvalue, it could be move-constructed --if move-constructor defined--).
They don't need to be cleaned. The designer of the class decided it would be a good idea to leave the moved-from object zero initialized.
Note that a situation where is does make sense is for objects managing resources that get released in the destructor. For instance, a pointer to dynamically allocated memory. Leaving the pointer in the moved-from object unmodified would mean two objects managing the same resource. Both their destructors would attempt to release.
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