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

Dmitry Marakasov amdmi3 at amdmi3.ru
Thu Feb 21 11:58:10 PST 2013


Hi!

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

The same problem applies to most containers, but, for example, in
std::vector it is solved by checking whether a template type has
non-throwing move constructor.

However, with pair this does not apply:

--- utility header from libc++
struct pair {
    ...
    pair(pair&&) = default;
---

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

I lean towards the former, as safe default move constuctors should be
always generated probably, and specific ones may be really hard to
implement for more complex types (tuples).

I've written a small program which demonstrates the problem:

https://gist.github.com/AMDmi3/5005557

tested it on FreeBSD current with clang-3.2 and libc++.

The same problem also exists with gcc/libstdc++.

-- 
Dmitry Marakasov   .   55B5 0596 FF1E 8D84 5F56  9510 D35A 80DD F9D2 F77D
amdmi3 at amdmi3.ru  ..:  jabber: amdmi3 at jabber.ru    http://www.amdmi3.ru



More information about the cfe-dev mailing list