Move semantics is a set of semantic rules and tools of the C++ language. It was designed to move objects, whose lifetime expires, instead of copying them. The data is transferred from one object to another. In most cases, the data transfer does not move this data physically in memory.
Move semantics allows you to avoid unnecessary copies when working with temporary objects that are about to evaporate, and whose resources can safely be taken from that temporary object and used by another.
Move semantics aim to avoid the copying of data from temporary objects by instead stealing the memory location of where the object resides. This behaviour is implemented through the use of a move constructor and move assignment operator that act only on rvalue references.
std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
I believe that the standards committee originally attempted to make it so move constructors would not be allowed to throw exceptions, but (at least as of today) found that trying to enforce that had too many pitfalls.
Proposal N3050, "Allowing Move Constructors to Throw (Rev 1)", has been incorporated into the draft standard. Essentially the proposal adds the capability for move constructors to throw, but to disallow 'throwing' moves to be used for certain operations where strong exception safety guarantees were needed (the library will fall back to copying the object if a non-throwing move isn't available).
If you mark a move constructor as non-throwing (noexcept
) and an exception is thrown, std::terminate() will be called.
It might also be worth reading a blog article by David Abrahams that discusses the issues that N3050 was intended to address:
Depends on the type being moved from. It's possible to explicitly throw an exception, of course, from a move ctor, but also to implicitly call a copy ctor for a subobject from a move ctor. That copy ctor might do something that may throw, such as allocate memory. So, for the source object, the minimum guarantee is the original value may or may not remain, but it should still be in a destructable state.
For the object being moved to, it's the same as throwing from a ctor in current C++: destroy any constructed bases and members, execute the ctor's function try handler, if any, then propagate the exception. Details are in N3225 §15.2p2.
In particular, note that containers require their allocator types not have throwing move ctors:
Such move construction of the allocator shall not exit via an exception. [N3225 §23.2p8]
This allows the containers to move allocators around and use those allocators to clean up their items in the case of an exception when moving or copying items.
Your question then amounts to a question about Exception Guarantees. There are 3 types of Exceptions Guarantees (that apply to functions):
When you compose your function, you usually pick up existing functions with their own guarantees. It is difficult to increase the exception guarantee, that is your are generally limited by the weakest guarantee used.
W.r.t your question, it takes at least a Strong Exception Guarantee for the original object to be left untouched if an exception is thrown.
So, what happens if an exception is thrown during move-construction ? It depends on the guarantees exhibited by the sub-objects and the way you combined the calls...
In terms of exceptions guarantees, it means that by default, if all of the subobjects' constructors at least meet the Basic Exception Guarantee, then your move constructor will too, without any special care.
However, even if all the subobjects' constructors meet the Strong Exception Guarantee, it's unlikely you'll succeed in having your own move constructor meet it: this is the same issue that chaining transactions does not yield a transaction.
If only one of the subobjects' constructors may throw, and it meets the Strong Exception Guarantee, then your move constructor will naturally meet it itself if you initialize the throwing object first.
Hope this helped... exceptions are a wild beast to tame :)
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