← Patterns

Copy-and-swap

123456789101112131415161718192021222324252627282930313233343536373839404142434445#include <utility> class resource { int x = 0; }; class foo { public: foo() : p{new resource{}} { } foo(const foo& other) : p{new resource{*(other.p)}} { } foo(foo&& other) : p{other.p} { other.p = nullptr; } foo& operator=(foo other) { swap(*this, other); return *this; } ~foo() { delete p; } friend void swap(foo& first, foo& second) { using std::swap; swap(first.p, second.p); } private: resource* p; };

This pattern is licensed under the CC0 Public Domain Dedication.

Requires c++11 or newer.

Intent

Implement the assignment operator with strong exception safety.

Description

The copy-and-swap idiom identifies that we can implement a classes copy/move assignment operators in terms of its copy/move constructor and achieve strong exception safety.

The class foo, on lines 7–45, has an implementation similar to the rule of five, yet its copy and move assignment operators have been replaced with a single assignment operator on lines 24–29. This assignment operator takes its argument by value, making use of the existing copy and move constructor implementations.

To implement the assignment operator, we simply need to swap the contents of *this and the argument, other. When other goes out of scope at the end of the function, it will destroy any resources that were originally associated with the current object.

To achieve this, we define a swap function for our class on lines 36–41, which itself calls swap on the class’s members (line 40). We use a using-declaration on line 38 to allow swap to be found via argument-dependent lookup before using std::swap — this is not strictly necessary in our case, because we are only swapping a pointer, but is good practice in general. Our assignment operator then simply swaps *this with other on line 26.

The copy-and-swap idiom has inherent strong exception safety because all allocations (if any) occur when copying into the other argument, before any changes have been made to *this. It is generally, however, less optimized than a more custom implementation of the assignment operators.

Note: We can typically avoid manual memory management and having to write the copy/move constructors, assignment operators, and destructor entirely by using the rule of zero

Contributors

  • Mattijs Kneppers
  • Joseph Mansfield

Last Updated

23 February 2018

Source

Fork this pattern on GitHub

Share