24

I've been reading some contradicting articles in regards whether move constructors/assignment is allowed to throw or not.

Therefore I'd like to ask whether move constructors/assignments are allowed to throw in the final C++11 standard?

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
ronag
  • 49,529
  • 25
  • 126
  • 221
  • I didn't see anything in the standard about move constructors not being allowed to throw, but I did see that "The implicitly-declared move constructor for class X will have the form `X::X(X&&)`", and I don't see `noexcept` in there. – Seth Carnegie Feb 12 '12 at 15:15
  • In the final draft, I don't see `noexcept` declared for any function... – ronag Feb 12 '12 at 15:20
  • @ronag: Are you sure you're looking? Because I opened up N3337 and just searched for "`noexcept`" and immediate got some class's `swap` function. – Nicol Bolas Feb 12 '12 at 17:03
  • @NicolBolas: I did the same, only place I found was for declval, N3092. Where did you get N3337? – ronag Feb 12 '12 at 17:09
  • 1
    @ronag: From the [pre-Kona mailing](http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2012/#mailing2012-01) for this year on the website. It's basically a free copy of C++11, with typos corrected. Also, N3092 is *ancient*. That's from 2010; I don't think had `noexcept` in the standard yet. Or if they did, it was still new and not farmed out to the standard library. – Nicol Bolas Feb 12 '12 at 17:12

2 Answers2

33

Are move constructors in general allowed to throw? Yes. Should they? No.

In general, nothing you do within them should be anything that could throw. You shouldn't be allocating memory, calling other code, or anything like that. The only reason to write a move constructor is to abscond with someone else's memory pointers and object references. You should be copying a few basic types and nulling out the values in the other object. Those things shouldn't throw.

So while it is allowed, it's not a good idea. If you're doing it, rethink what you're doing in your move operations.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • I assume no stl types throw in the move constructor? The only places I should worry about it is with USD? – ronag Feb 12 '12 at 17:10
  • 10
    @ronag: If the std::type does not have a `noexcept` on its move constructor, it is allowed to throw. Specifically, some implementations of node-based containers have a throwing move constructor because each container must contain a heap-allocated end-node, even empty containers. Other implementations of these same containers do not have this design and therefore can (and are allowed to) have a noexcept move constructor. – Howard Hinnant Feb 12 '12 at 17:27
8

Here's to shed some further light on this.

It seems that std::vector in particular is picky about whether or not you declare your move constructors with noexcept. If you do, then std::vector will use them. If you don't then std::vector will resort to using your copy constructor instead. At least in some cases. Notably whenever it reshuffles items internally, after an internal array resize.

You can see the effects in this example, where noexcept is not declared:

http://coliru.stacked-crooked.com/a/285cd07a9a52da3b

And in this example, where it is:

http://coliru.stacked-crooked.com/a/d043774ec4c279ec

In the first example, std::vector uses the copy constructor already at the second and third insertion with push_back. In the second example, it does the same operation, but with the move constructor instead.

bjaastad_e
  • 691
  • 6
  • 10