The copy-and-swap idiom is said to provide a strong exception guarantee. But in C++11, std::swap uses move operations.
Consider the following code:
class MyClass
{
AClass x;
CanThrowIfMoved throwingObject;
MyClass(MyClass&& other) noexcept
x(std::move(other.x)),
throwingObject(std::move(other.throwingObject))
{ }
friend void swap(MyClass& first, MyClass& second) noexcept
{
using std::swap;
swap(first.x, other.x);
swap(first.throwingObject, other.throwingObject);
}
MyClass& operator=(MyClass other) noexcept
{
swap(*this, other);
return *this;
}
};
If throwingObject
throws during the swap, the strong exception guarantee is broken.
The noexcept
keywords don't enforce anything during compile time. throwingObject
can still throw, the only difference is that the program will violently terminate
. I don't think crashing the entire application when an exception occurs counts as a strong exception guarantee.
Does this mean that copy-and-swap no longer enforces the strong exception guarantee in C++11?
Similar questions
This question is similar, but it's targeted at using the standard library. I'm interested in what this issue means for the strong exception guarantee of the copy-and-swap idiom.
This question discusses how to use noexcept
in the copy-and-swap idiom, but only discusses the copy. Not the swap, which is where the problem seems to be.
Instead of directly invoking swap
in the swap
member method, use a helper function template, that checks at compile time the noexcept
guarantee:
friend void swap(MyClass& first, MyClass& second) noexcept
{
util::swap_noexcept(first.x, other.x);
util::swap_noexcept(first.throwingObject, other.throwingObject);
}
namespace util
{
template <typename ...Args>
void swap_noexcept(Args&&... args) noexcept
{
using std::swap;
static_assert(noexcept(swap(std::forward<Args>(args)...)), "requires noexcept");
swap(std::forward<Args>(args)...);
}
}