[cfe-dev] Not exception-safe default move constructors (demonstrated on std::pair)

John McCall rjmccall at apple.com
Thu Feb 21 14:50:32 PST 2013


On Feb 21, 2013, at 11:58 AM, Dmitry Marakasov <amdmi3 at amdmi3.ru> wrote:
> It turns out that default move constructors are not exception-safe -
> e.g. when an object is constructed with move constructor, it may happen
> that some of its members are constructed with move constuctors, then
> others with copy constructors. In case of such a copy constructor
> throwing an exception, already moved members will be freed, and original
> object will be left with a set of empty memebers.
> 
> The problem is described here:
> http://cpp-next.com/archive/2009/10/exceptionally-moving/
> 
> and may be demonstrated on std::pair:
> 
> - You have two classes:
>  A, which has a proper move constructor which doesn't throw
>  B, which which only has copy constructor which may throw
> - You have an std::pair<A, B>
> - You move a pair
>  std::pair<A, B> pair1;
>  try {
>    std::pair<A, B> pair2(std::move(a));
>  }
> 
> What happens:
> - A part is constructed with move ctor. This is obviously destructive
>  to pair1.
> - B part is constructed with copy ctor, as it doesn't have move constuctor.
> - Now, that copy constructor throws (which is pretty expectable is it
> likely allocates resources). After this, as A part was already moved,
> we're left with corrupted pair1 (with empty A part).

In addition to Howard's response, I just want to point out that pair1 isn't
really "corrupted";  operations on it will still work correctly, including its
eventual destruction.  It's just been partially "emptied", so the operations
won't reflect the original value before the partial move.

Your complaint is really that move construction isn't *transactional*:
it does not promise to either fully succeed or else have no effect other
than to fail.  This would be a very strong guarantee for the language to
make;  it would involve a huge amount of overhead (move-assigning
moved components back into their source) and is probably not possible
in general.

> Either the default constructor generated by clang is unsafe, or there
> should be custom, safe move constuctor with corresponding enable_if.

Well, clang and libc++'s behavior here is not up for debate;  they're both
directly dictated by the standard, which is why gcc and libstdc++ agree.
If you don't agree with this, the appropriate action is to take it to the
C++ committee.

John.



More information about the cfe-dev mailing list