Consider the following code (assume that SomeClass has move constructor and fields like pointers which would go invalid after object gets its content swaped with another object):
SomeClass data;
std::list queue;
try { queue.push_back(std::move(data)); }
catch(std::bad_alloc)
{
data.doThingsUsingObjectData(); //Can I do this here?
return;
}
data.doThingsUsingObjectData(); //Definitelly can't do this here - object was invalidated
The point is - if bad_alloc is thrown upon adding object to STL with std::move(), would that mean the object I tried to add to STL by rvalue is actualy still valid and I can access it without worrying about undefined behaviour?
A std::list stores its elements in nodes. When you add an element a new node is allocated, then the element is stored in the node (via a call to std::allocator_traits<A>::construct, which typically does a placement-new to construct the object in place inside the node), and then finally the node is added to the list, by updating the pointers of the new node and the adjacent node(s) to link it into the list.
If a bad_alloc exception is thrown it can only be from allocating the new node, or from constructing the element inside the node (because updating the pointers won't throw anything).
If the exception happens when allocating the node object then it is very likely that the object has not been moved from yet, because no attempt has been made to move-construct a new element (you can't do that until you have a node to construct it into!). There's no guarantee that the container doesn't create intermediate variables before constructing the final element inside the node, but that would be a poor quality implementation, as there is no reason to do that.
If the class has a non-throwing move constructor then you know that the exception must have come from the node allocation. Otherwise, if the exception comes from constructing the element then the state of the rvalue argument will be dictated by the exception-safety guarantees of the class in question.
So in short, if the std::list implementation is bad, or the object being inserted can throw during move construction and doesn't have the strong exception-safety guarantee, then the rvalue argument might be left in a moved-from state. But otherwise, you should be able to rely on it being unmodified.
It depends why the exception was thrown, but generally speaking, No. The object is in unspecified state after the move operation. Please refer to this question.
The container may and may not use SomeClass's move constructor, but when you are using std::move, you mark the object to be an rvalue reference, you should not be using an object after using it (or passing it around) as rvalue reference.
As a good practice, you should never use std::move if you think about reusing the object.
IIRC, the standard states that objects moved from, remain in unspecified state. That means that you can call member methods and they should work correctly as long as they don't rely on a specific state of the object. Reference needed
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