Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could it be possible to have types with move operations that throw in containers?

While explaining move operations on objects with a colleague, I basically said that move operations should not throw exceptions in a container because if the move operation fails, then there is no way to bring back the original object reliably. Thinking about this more, I'm wondering if that is not correct and that if a move operation that does throw, it could revert the original object back to it's original state.

The reason for this, is that if an object can throw, then it would throw not due to copying or moving the contained objects from the old to the new address, but throw if a resource failed to be acquired. So all of the original information should still be there. If this is the case, then should the compiler not be able to reverse the operations that it did to reconstitute the original object?

It could be possible for an operation to be one way, like moving an integer, but in that case it could just terminate the application, and perhaps if the developer wanted to avoid the one way operation could use a swap method instead.

This would only be possible on default move operators, as if there are any additional logic, it may be difficult for the compiler to do a reverse partial transform.

Am I oversimplifying things? Is there something that I missed which keeps containers from moving objects without a non-throwing move constructor/operator?

like image 906
Adrian Avatar asked May 29 '18 17:05

Adrian


People also ask

Why noexcept for move constructor?

noexcept is nice for two reasons: The compiler can optimize a little better because it doesn't need to emit any code for unwinding a call stack in case of an exception, and. It leads to incredible performance differences at runtime for std::vector (and other containers, too)

Which is not a container class?

Which are not full container classes in c++? Explanation: Container adaptors are not full container classes, but classes that provide a specific interface relying on an object of one of the container classes such as deque or list to handle the elements.

What is memory ownership for a container?

In C++, the term memory ownership refers to the entity that is responsible for enforcing the lifetime of a particular memory allocation.

Is an array a container?

Is an array a container? Arrays hold a set of elements of the same type in a contiguous memory location so, do they not qualify as containers? In most languages, an array would indeed qualify as a container.


1 Answers

You can use types with throwing moves in containers like vector which can move their elements. However, such containers will not use throwing move operations.

Let's say you have a vector of 10 throwing move elements. And the vector needs to resize itself. So it moves 5 objects to the new memory, but the 6th throws. Well, that's OK; construction failed, so the assumption is that the value of the 6th object is fine. That is, whatever that type's exception guarantee is will be how things work.

But then, because the movement of one object failed, vector needs to move the last 5 objects back to the first array, since vector is trying to provide a strong exception guarantee. That's a problem, since the move back can itself fail.

C++ in general does not have valid answers when the process of repairing a failure itself fails. You can see that in exceptions; you can't emit an exception from a destructor that is called during the process of unwinding due to an exception failure. std::terminate happens in this case.

The same goes for vector. If the move back were to fail, vector has no sane answer. As such, if vector cannot guarantee that restoring its previous array state is noexcept, then it will use copying, since that can provide that guarantee.

like image 109
Nicol Bolas Avatar answered Oct 20 '22 17:10

Nicol Bolas