"C++ Concurrency in Action second edition" has an example of thread-safe stack implementation, and the following is the code for pop:
template <typename T>
std::shared_ptr<T> threadsafe_stack<T>::pop()
{
std::lock_guard<std::mutex> lock(m);
// `data` is a data member of type `std::stack<T>`
if(data.empty()) throw empty_stack(); // <--- 2
std::shared_ptr<T> const res(
std::make_shared<T>(std::move(data.top()))); // <--- 3
data.pop(); // <--- 4
return res;
}
The book has the following explanation for this code:
The creation of res (3) might throw an exception, though, for a couple of reasons: the call to std::make_shared might throw because it can’t allocate memory for the new object and the internal data required for reference counting, or the copy constructor or move constructor of the data item to be returned might throw when copying/moving into the freshly- allocated memory. In both cases, the C++ runtime and Standard Library ensure that there are no memory leaks and the new object (if any) is correctly destroyed. Because you still haven’t modified the underlying stack, you’re OK.
Does this explanation correct?
If data item's move constructor throws, and the data item is corrupted. Although this implementation avoid memory leak, the state of the stack has been damaged/modified (not strong exception safe), and latter read will get corrupted data. Right?
So it seems that this implementation works, only if the move constructor doesn't throw (or at least, even if it throws, it keeps the data item unmodified)?