I’m writing a mutex protected stack with the following function for popping a value off the top with possible failure:
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lock(mutex_);
if (ctr_.empty())
return false;
value = std::move(ctr_.back());
ctr_.pop_back();
return true;
}
I’m using a std::vector as the underlying container. To store a non-copyable T in the stack (e.g. std::unique_ptr) I have used std::move to take the T off the back of the vector, otherwise a copy is made. Two questions: a) Is this correct? Will the T be moved or copied? b) I’m concerned about exception safety. If the move throws, then the stack will not be popped, but the top value may be in a half-moved state. Is this possible and how do I solve?
a) It will be moved, assuming it has a move constructor. For types that have defined a copy constructor but not a move constructor, it will be copied.
b) If you need the strong exception guarantee, then you should use
std::move_if_noexceptwhich only enables moving when the input provides anoexcept()move constructor. That way, if the move constructor can throw, it will resort to making a copy so if an exception is thrown the object is left unchanged on the stack.std::move_if_noexceptwas explicitly provided to help provide the strong guarantee in cases like this.Edit: As Howard Hinnant points out, the current code example is using move assignment, not move construction, so
std::move_if_noexceptwill not likely do what you want. To solve it while using assignment, you’ll need to write your own wrapper which is based on thestd::move_if_noexcept: