More C++ Idioms/Copy-and-swap

= Copy-and-swap =

Intent
To create an exception safe implementation of overloaded assignment operator.

Also Known As
Create-Temporary-and-Swap

Motivation
Exception safety is a very important cornerstone of highly reliable C++ software that uses exceptions to indicate "exceptional" conditions. There are at least 3 types of exception safety levels: basic, strong, and no-throw. Basic exception safety should be offered always as it is usually cheap to implement. Guaranteeing strong exception safety may not be possible in all the cases. The copy-and-swap idiom allows an assignment operator to be implemented elegantly with strong exception safety.

Solution and Sample Code
Create a temporary and swap idiom acquires new resource before it forfeits its current resource. To acquire the new resource, it uses RAII idiom. If the acquisition of the new resource is successful, it exchanges the resources using the non-throwing swap idiom. Finally, the old resource is released as a side effect of using RAII in the first step. Some variations of the above implementation are also possible. A check for self assignment is not strictly necessary but can give some performance improvements in (rarely occurring) self-assignment cases.

copy elision and copy-and-swap idiom

Strictly speaking, explicit creation of a temporary inside the assignment operator is not necessary. The parameter (right hand side) of the assignment operator can be passed-by-value to the function. The parameter itself serves as a temporary.

This is not just a matter of convenience but in fact an optimization. If the parameter (s) binds to an lvalue (another non-const object), a copy of the object is made automatically while creating the parameter (s). However, when s binds to an rvalue (temporary object, literal), the copy is typically elided, which saves a call to a copy constructor and a destructor. In the earlier version of the assignment operator where the parameter is accepted as const reference, copy elision does not happen when the reference binds to an rvalue. This results in an additional object being created and destroyed.

In C++11, such an assignment operator is known as a unifying assignment operator because it eliminates the need to write two different assignment operators: copy-assignment and move-assignment. As long as a class has a move-constructor, a C++11 compiler will always use it to optimize creation of a copy from another temporary (rvalue). Copy-elision is a comparable optimization in non-C++11 compilers to achieve the same effect.

Not every class benefits from this style of assignment operator. Consider a String assignment operator, which releases old memory and allocates new memory only if the existing memory is insufficient to hold a copy of the right hand side String object. To implement this optimization, one would have to write a custom assignment operator. Since a new String copy would nullify the memory allocation optimization, this custom assignment operator would have to avoid copying its argument to any temporary Strings, and in particular would need to accept its parameter by const reference.

Related Idioms

 * Resource Acquisition Is Initialization
 * Non-throwing swap