views:

117

answers:

2

In an answer to a question about std::stack::pop() I claimed that the reason pop does not return the value is for exception safety reason (what happens if the copy constructor throws).

@Konrad commented that now with move semantics this is no longer relevant. Is this true?

AFAIK, move constructors can throw, but perhaps with noexcept it can still be achieved.

For bonus points what thread safety guarantees can this operation supply?

+2  A: 

Of course, not every type is move-enabled and C++0x even allows throwing move constructors. As long as constructing the object from an rvalue may throw it cannot be exception-safe. However, move semantics allows you to have many types that are nothrow-constructible given an rvalue source.

Conditional support for this could be done with SFINAE. But even without such a conditional member function nothing stops you from writing:

auto stack = ...;
auto elem = std::move_if_noexcept(stack.back());
stack.pop_back();

which is makes the strong exception guarantee even in case your move constructor doesn't give the strong guarantee.

sellibitze
Yeah but can't you use `has_nothrow_move_constructor<T>` to create the method only `T` has a no-throw move constructor?
Motti
@Motti: The problem is that you would have different interfaces and behaviors (not just implementations) depending on whether the stored objects have move constructor, so that would not really be a good idea.
David Rodríguez - dribeas
@dribeas: would it be bad for there to be a pop function that returns something if there's a move constructor, and void if there isn't? In the common use cases either you know the stack's value type (e.g. if it's `int`, you can use the return value, and if you use the return value when you shouldn't your code doesn't compile), or else you're writing generic code and don't know the type (in which case you stick with the old interface).
Steve Jessop
+1  A: 

As for the bonus question, that would offer no thread-safety. Consider that, as an example, most implementations of std::vector have three data elements (pointer to beginning of memory, pointer one beyond end of used data, pointer one beyond end of allocated memory). Move semantics allow you to move the contents of the vector without the need to reallocate and copy values, but that has nothing to do with thread safety. You would have to use thread-safe constructs to make the structure thread safe (as moving does not imply by any means atomic)

David Rodríguez - dribeas