C++: Copy and Swap

Bjarne-stroustrup
 


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

#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;
};

Subscribe to TFE Times

Enter your email address to become a member of TFE Times today!