Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(Why) should a move constructor or move assignment operator clear its argument?

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 doubles.)

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 a std::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?

like image 221
Lynn Avatar asked Sep 09 '16 14:09

Lynn


People also ask

What is the difference between move constructor and move assignment?

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.

What is the purpose of a move constructor?

A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying.

What is advantage of move constructor in C++?

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.

What is the difference between a move assignment and a copy assignment?

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--).


1 Answers

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.

like image 89
juanchopanza Avatar answered Sep 30 '22 18:09

juanchopanza