The A swap function must not fail rule of CppCoreGuidelines says:
swapis widely used in ways that are assumed never to fail and programs cannot easily be written to work correctly in the presence of a failingswap. The standard-library containers and algorithms will not work correctly if a swap of an element type fails.
The Make swap noexcept rule of CppCoreGuidelines says:
A
swapmust not fail. If aswaptries to exit with an exception, it’s a bad design error and the program had better terminate.
Consider a class C, for which a noexcept move constructor, noexcept move assignment operator and noexcept swap() cannot be implemented. Its copy constructor and copy assignment operator are noexcept(false), therefore std::swap<C>() is noexcept(false) too. Should a friend swap() for this class be declared noexcept anyway so as to terminate in case of an exception and avoid the "bad design error"?
The described class C is a rare case. However, C++03 classes, which define a destructor, copy constructor or copy assignment operator, lack noexcept move operations. A custom swap() for such classes may be non-throwing, though not declared noexcept. If they don't have a custom swap(), the std::swap() specialization calls their copy operations, and so can throw. Do such classes commit the "bad design error"?
Can classes with a throwing swap() be used in standard-library containers and algorithms? Does the standard specify that swap() must not throw exceptions or be noexcept(true) for some standard-library functionality to work? If some parts of the standard library do not work correctly when swap() throws, this must be spelled out in the standard somewhere. The standard library often relies on the destructor to be noexcept; falls back on exception-safe copying when the move operations are noexcept(false). I wonder where swap()'s exception specification stands in this regard.
EDIT [for those who cannot imagine a class with a throwing swap()]: my class C (implemented before C++11 by someone else) is externally, optionally reference-counted. A specific object of this class C is reference-counted if a global container contains its address (this). When a reference-counted object is copied or moved into or swapped with a not-reference-counted object (or vice versa), the reference counts have to be changed. Manipulating reference counts is very complicated. Not only does it (optionally) allocate memory, but performs other operations that are more likely to fail than operator new. Wrapping each object into a unique_ptr would cause a huge overhead for the most common not-reference-counted case. Of course, such classes are not commonplace, but I think there are enough of throwing swap()s around to deserve some consideration.
EDIT of the previous EDIT: special member functions must (conditionally) change reference counts because they depend on the object's value. Each object contains a handle to an external resource, which is optionally reference counted. So when the value of a reference-counted object is changed during the copying/moving/swapping with a non-reference-counted object, the reference count of its previous handle has to be decreased and the reference count of its new handle (from the other object) has to be increased.