23

I know std::queue::pop() returns void. For two reasons:

  1. exception safety: something might throw after removing the element
  2. to be able to return the value by reference

Fine.

Now if I understand the new C++11 move semantics correctly, the second is no longer a valid argument.

So... the only thing preventing std::queue to have a pop-like function returning the value lies in the possibility that the move constructor throws?

I have a hard time thinking of situations where such a move constructor would throw. Who knows of an example?

I guess the same goes for std::stack::pop(), std::vector::pop_front(), std::vector::pop_back(), std::deque::pop_front(), std::deque::pop_back(), std::list::pop_front(), std::list::pop_back() and what not.

Michel de Ruiter
  • 7,131
  • 5
  • 49
  • 74
  • Those are really two questions. An example for a throwing move constructor and a returning `pop`. – pmr Feb 08 '12 at 10:48
  • I need an example of a throwing move constructor to understand why we can't have the returning `pop`. – Michel de Ruiter Feb 08 '12 at 10:51
  • 3
    What about types which don't have a move constructor at all? – jalf Feb 08 '12 at 14:02
  • 1
    Well, since not all types are movable efficiently, the 2nd reason is still valid. The mere addition of move semantics to the language doesn't make all by-value returns performance-wise no-ops, its about the types using them to their advantage and not all types can do that. And the 1st reason, well what situations one can think of in practice and what situations are allowed by the standard and *somebody* at *some* point in time *could* *possibly* come up with are two different things. – Christian Rau Feb 08 '12 at 17:45

3 Answers3

6

There aren't many cases where std::move() can throw in the standard library but there are cases. For example, if the container uses a stateful allocator, its children also use this allocator, but it won't be moved to a result: this would rather get a default constructed version of an allocator (if I remove correctly). Given that the allocators are stateful this means that the object can't be moved and thus the move construction fails with an exception. Why does this type then have a move constructor? Well, because it might be instantiated with non-stateful allocator in which case moving won't throw. In addition, once we move to user defined classes we have no idea under which condition moving them might throw.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • You end up giving so many questions an interesting twist. Some day when I have the time I'm going to go through your profile and read all your answers to everything. – odinthenerd May 14 '14 at 14:37
5

Using clever SFINAE techniques it would indeed be possible to have an atomic non-throwing pop_and_move() for just datatypes that implement no-throwing move or no-throwing copy.

There is even a noexcept() construct available to see if something might throw.

One of the new concepts in C++11 in particular that extends SFINAE is that if the body doesn't compile the function doesn't exist. Thus one could implement based on noexcept().

I would say for backward compatibility the function would need a new name, which therefore allows it to co-exist with the existing functionality of calling them separately, not breaking containers of types that do not have the semantics to allow it.

CashCow
  • 30,981
  • 5
  • 61
  • 92
  • Could you elaborate on the extension of SFINAE in C++11 (a standard reference would be nice)? I haven't heard about that at all and would like to readmore. – Grizzly Feb 08 '12 at 15:41
  • 1
    It was mentioned by Alexandrescu in his talk on variadic templates in the Going Native conference. As part of the "substitition failure is not an error" principle, if the body would not compile this is considered a substitution failure too (thus ignore this specialisation). With noexcept() it is probably possible to already create a function that would use move if available and not-throwing, then would use copy as second choice if that is available and not-throwing, and fail to compile otherwise. – CashCow Feb 08 '12 at 16:36
  • 1
    Sounds promising! This answer isn't the most direct answer to my questions, but it's actually what I was looking for without knowing. – Michel de Ruiter Feb 11 '12 at 20:34
  • 1
    The talks are available on msdn channel9. http://channel9.msdn.com/Events/GoingNative/GoingNative-2012 in particular follow Alexandrescu's talks. (Variadic templates is quite complex, static if a bit less so but it will show you what they are capable of putting into libraries dependent on the template parameters, even without concepts as a language feature). – CashCow Feb 13 '12 at 10:49
1

Another problem is, that not every class really benefits from moving, i.e., they might only have a copy ctor.

struct DontLikeMoves{
  // some data, whatever...
  DontLikeMoves(DontLikeMoves const& other){
    // might throw, who knows!
    // and this will even get called for rvalues
  }
};
Xeo
  • 129,499
  • 52
  • 291
  • 397