Question
Copy-and-Swap Idiom in C++: What It Is, Why It Matters, and When to Use It
Question
In C++, what is the copy-and-swap idiom, and when should it be used? What problems does it solve in class design and assignment operators? Also, did the recommended approach change with C++11 and move semantics?
Related areas of confusion often include:
- how to implement a copy constructor and copy assignment operator safely
- whether a shared helper function can be used for copying and assignment
- how copy elision interacts with this pattern
- how resource-owning classes behave when managing dynamic memory
Short Answer
By the end of this page, you will understand what the copy-and-swap idiom is in C++, why it is used to implement assignment safely, and how it helps with exception safety and self-assignment. You will also see how C++11 move semantics changed the way this idiom is used in modern C++ code.
Concept
The copy-and-swap idiom is a common C++ technique for implementing the assignment operator safely and cleanly.
At a high level, it works like this:
- Make a copy of the right-hand side object.
- Swap the current object's data with the copy.
- Let the temporary copy go out of scope and clean up the old data.
A typical form looks like this:
class Buffer {
public:
Buffer& operator=(Buffer other) {
swap(*this, other);
return *this;
}
friend void swap(Buffer& a, Buffer& b) noexcept {
using std::swap;
swap(a.size, b.size);
swap(a.data, b.data);
}
private:
std::size_t size{};
int* data{};
};
The parameter other is passed by value, which means it is copied (or moved) before the function body runs. Once the copy succeeds, the function swaps the current object with that local copy.
What problem does it solve?
The idiom mainly solves three issues:
1. Exception safety
If copying the right-hand side fails, the current object is not modified.
Mental Model
Think of your object like a person carrying a backpack.
- The current object is wearing an old backpack.
- The right-hand side object represents a new backpack setup.
- Instead of emptying the old backpack item by item and risking mistakes, you first prepare a complete new backpack.
- Then you swap backpacks.
- The temporary person walks away with the old backpack, and when they leave, the old backpack is destroyed safely.
This model explains why the idiom is safe:
- if preparing the new backpack fails, you keep the old one unchanged
- if it succeeds, the swap is quick and simple
- cleanup happens automatically when the temporary object is destroyed
So copy-and-swap is really: build the replacement first, then trade places.
Syntax and Examples
Core syntax
A classic copy-and-swap assignment operator looks like this:
class MyClass {
public:
MyClass(const MyClass& other); // copy constructor
~MyClass();
MyClass& operator=(MyClass other) {
swap(*this, other);
return *this;
}
friend void swap(MyClass& a, MyClass& b) noexcept {
using std::swap;
swap(a.value, b.value);
}
private:
int* value{};
};
Beginner-friendly example
Here is a small class that owns a dynamic array:
#include <algorithm>
#include <cstddef>
#include <iostream>
class IntArray {
public:
IntArray(std::size_t size = )
: (size), (size ? [size] : ) {}
( IntArray& other)
: (other.size_), (other.size_ ? [other.size_] : ) {
std::(other.data_, other.data_ + size_, data_);
}
~() {
[] data_;
}
IntArray& =(IntArray other) {
(*, other);
*;
}
{
std::swap;
(a.size_, b.size_);
(a.data_, b.data_);
}
{
data_[index] = value;
}
{
data_[index];
}
{
size_;
}
:
std:: size_{};
* data_{};
};
Step by Step Execution
Consider this code:
IntArray a(2);
a.set(0, 10);
a.set(1, 20);
IntArray b(2);
b.set(0, 1);
b.set(1, 2);
a = b;
Let us trace a = b;.
Before assignment
aowns memory containing:[10, 20]bowns memory containing:[1, 2]
Step 1: Call assignment operator
The compiler calls:
a.operator=(b)
Because the parameter is passed by value, b is copied into a local object named other.
Real World Use Cases
Copy-and-swap is most useful in classes that own resources directly.
Common examples
Dynamic memory wrappers
A custom container, matrix, buffer, or string-like class may own raw heap memory.
File or handle wrappers
If a class owns a low-level handle and supports copying by duplicating the handle, safe assignment logic is needed.
Legacy C++ codebases
Older projects often have custom resource-owning classes written before modern standard library usage became common.
Educational implementations
When learning the Rule of Three or Rule of Five, copy-and-swap is a clean way to understand safe assignment.
Example scenarios
- a
Matrixclass reallocates memory when assigned a matrix of different size - a
TextBufferclass stores a manually managed character array - a
Imageclass owns pixel data and must avoid leaks during assignment - a custom
Stringclass must support self-assignment and exception safety
When it is less necessary
If you use standard types like these:
std::vectorstd::stringstd::unique_ptr
Real Codebase Usage
In real projects, developers usually prefer the simplest safe design.
Modern pattern: Rule of Zero first
If your class is composed of well-behaved members, write this:
class UserProfile {
public:
std::string name;
std::vector<int> scores;
};
No custom destructor, copy constructor, or assignment operator is needed.
This is usually better than implementing copy-and-swap manually.
When custom assignment still appears
Developers still use custom assignment operators when:
- wrapping a C library resource
- maintaining older code with raw pointers
- implementing low-level containers
- needing a strong exception guarantee for replacement-style assignment
Common patterns around copy-and-swap
1. Custom swap
A class defines a swap function that swaps all resource-owning members.
friend void swap(Buffer& a, Buffer& b) noexcept {
using std::swap;
swap(a.size_, b.size_);
swap(a.data_, b.data_);
}
2. By-value assignment
Common Mistakes
1. Forgetting to implement a proper swap
If swap does not exchange every important member, the object may become inconsistent.
Broken example:
friend void swap(IntArray& a, IntArray& b) noexcept {
using std::swap;
swap(a.data_, b.data_);
// forgot to swap size_
}
Why it is wrong:
- the pointer and size no longer match
- later access may read invalid memory
2. Writing unsafe manual assignment first
Beginners often write assignment like this:
IntArray& operator=(const IntArray& other) {
delete[] data_;
size_ = other.size_;
data_ = new int[size_];
std::copy(other.data_, other.data_ + size_, data_);
return *this;
}
Problems:
- if
newthrows, the object is already damaged - self-assignment can cause trouble because you delete your own data before copying
3. Ignoring self-assignment
Comparisons
Copy-and-swap vs manual copy assignment
| Approach | Main idea | Exception safety | Self-assignment safety | Complexity |
|---|---|---|---|---|
| Copy-and-swap | Copy first, then swap | Strong, if copy and swap are safe | Usually automatic | Simpler |
| Manual assignment | Rebuild current object in place | Easy to get wrong | Must be handled carefully | More error-prone |
Pre-C++11 vs C++11 and later
| Version | How copy-and-swap fits |
|---|---|
| Pre-C++11 | Very common way to write safe assignment for resource-owning classes |
| C++11+ | Still valid, but move semantics and Rule of Zero reduce how often you need it |
Cheat Sheet
Copy-and-swap quick reference
Purpose
- Implement copy assignment safely
- Handle self-assignment naturally
- Provide strong exception safety
Core pattern
class T {
public:
T(const T& other);
T& operator=(T other) {
swap(*this, other);
return *this;
}
friend void swap(T& a, T& b) noexcept {
using std::swap;
swap(a.member1, b.member1);
swap(a.member2, b.member2);
}
};
How it works
otheris copied or moved into the parameter- swap current object with
other otherdestroys the old state when it goes out of scope
Benefits
- strong exception safety
- self-assignment safety
- simpler assignment code
Requirements
FAQ
What is the copy-and-swap idiom in C++?
It is a way to implement assignment by first copying the source object, then swapping its contents with the current object. The old data is cleaned up automatically when the temporary copy is destroyed.
Why is copy-and-swap considered safe?
Because the current object is not modified until copying succeeds. If copying throws an exception, the object stays unchanged.
Does copy-and-swap handle self-assignment?
Yes, in most normal implementations it does. Since the right-hand side is copied first, obj = obj; does not corrupt the object.
Is copy-and-swap still useful in C++11 and later?
Yes, but it is less universally needed. Move semantics and standard RAII types often make custom assignment operators unnecessary.
Is operator=(T other) better than operator=(const T& other)?
Not always. The by-value form is elegant and safe, but a separate move assignment operator can sometimes be more efficient.
Should I always use copy-and-swap for resource-owning classes?
No. First consider whether the class should own raw resources directly at all. If you can use std::vector, std::string, or smart pointers, that is usually better.
What is the relationship between copy-and-swap and the Rule of Three?
If your class manually manages a resource, you often need a destructor, copy constructor, and copy assignment operator. Copy-and-swap is one way to implement the assignment part safely.
What is the relationship between copy-and-swap and the Rule of Five?
Mini Project
Description
Build a small C++ class named TextBuffer that stores dynamically allocated character data and uses the copy-and-swap idiom for assignment. This project demonstrates safe resource management, self-assignment safety, and clean cleanup logic.
Goal
Create a resource-owning class that supports copying and assignment safely using copy-and-swap.
Requirements
- Create a
TextBufferclass that owns a dynamically allocated character array. - Implement a constructor, copy constructor, destructor, and assignment operator.
- Implement a
swapfunction that exchanges all important members. - Demonstrate copying, assignment, and self-assignment in
main(). - Print the stored text to show that assignment works correctly.
Keep learning
Related questions
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Casts Explained: C-Style Cast vs static_cast vs dynamic_cast
Learn the difference between C-style casts, static_cast, and dynamic_cast in C++ with clear examples, safety rules, and real usage tips.
C++ Lambda Expressions Explained: What They Are and When to Use Them
Learn what C++ lambda expressions are, why they exist, when to use them, and how they simplify callbacks, algorithms, and local logic.