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.
That gives you the strong exception guarantee:
- either the assignment succeeds completely
- or the object stays unchanged
2. Self-assignment safety
With copy-and-swap, obj = obj; works correctly without a special self-assignment check in most cases.
3. Code simplicity
Instead of manually deleting old resources, allocating new ones, and carefully handling every failure path, you centralize the risky work in the copy constructor and the cleanup in the destructor.
Why this matters in real C++
C++ often deals with resource management:
- dynamic memory
- file handles
- sockets
- mutex wrappers
- custom heap buffers
Whenever a class owns a resource, assignment becomes tricky. A bad assignment operator can cause:
- memory leaks
- double deletion
- partially updated objects
- invalid state after exceptions
Copy-and-swap is one way to write safer resource-owning classes.
The big idea
Instead of trying to modify the existing object carefully in place, you first build a safe replacement, then swap it in.
That is often simpler and safer than updating piece by piece.
What changed in C++11?
C++11 introduced move semantics, which changed the picture.
Before C++11, copy-and-swap was a very popular default strategy for writing assignment operators.
After C++11:
- passing by value may use a move instead of a copy for rvalues
- many classes can rely on the Rule of Zero by using standard library types like
std::vector,std::string, and smart pointers - sometimes a custom copy-and-swap assignment operator is no longer the best performance choice
So the idiom is still valid, but it is not always the first tool you should reach for in modern C++.
If your class manually manages a resource, copy-and-swap can still be useful. But if your class can be built from RAII standard types, the best solution is often to let the compiler generate special member functions or use defaults.
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 = 0)
: size_(size), data_(size ? new int[size] : nullptr) {}
IntArray(const IntArray& other)
: size_(other.size_), data_(other.size_ ? new int[other.size_] : nullptr) {
std::copy(other.data_, other.data_ + size_, data_);
}
~IntArray() {
delete[] data_;
}
IntArray& operator=(IntArray other) {
swap(*this, other);
return *this;
}
friend void swap(IntArray& a, IntArray& b) noexcept {
using std::swap;
swap(a.size_, b.size_);
swap(a.data_, b.data_);
}
void set(std::size_t index, int value) {
data_[index] = value;
}
int get(std::size_t index) const {
return data_[index];
}
std::size_t size() const {
return size_;
}
private:
std::size_t size_{};
int* data_{};
};
Why this works
When you do:
IntArray a(3);
IntArray b(5);
a = b;
these steps happen:
bis copied into the by-value parameterotheraswaps its internal data withotherothernow holdsa's old data- when
otheris destroyed, the old data is deleted
Why swap should be noexcept
The idiom works best when swap cannot throw exceptions. If swapping itself throws, the strong exception guarantee becomes harder to maintain.
That is why custom swap functions are usually written as noexcept when possible.
C++11 version with moves
In C++11 and later, the same by-value operator can benefit from move construction for temporaries:
IntArray a;
a = IntArray(10); // may move into the parameter instead of copying
That means the idiom became more flexible, although sometimes a dedicated move assignment operator is still more efficient.
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.
Now:
aowns:[10, 20]bowns:[1, 2]otherowns a separate copy:[1, 2]
If this copy fails due to an exception, a is still unchanged.
Step 2: Swap a and other
Inside the operator:
swap(*this, other);
After the swap:
aowns:[1, 2]otherowns:[10, 20]
Step 3: Return from the function
The function returns *this, which is a.
Step 4: Destroy other
The local variable other goes out of scope.
Its destructor runs and deletes the memory it owns.
That means the old data from a is cleaned up automatically.
Final state
anow contains a copy ofbbis unchangeda's old memory was deleted safely
This is why the idiom is attractive: the dangerous steps are isolated and cleanup is automatic.
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_ptrstd::shared_ptr
then you often do not need copy-and-swap manually, because those types already manage resources correctly.
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
One operator handles both copied lvalues and moved rvalues:
Buffer& operator=(Buffer other) {
swap(*this, other);
return *this;
}
3. Validation before replacement
A similar idea appears outside assignment too: create a valid replacement first, then commit the change only when ready.
4. Strong exception safety
This pattern is used whenever partial updates would be dangerous.
Performance note
In high-performance code, developers may prefer a dedicated copy assignment operator and dedicated move assignment operator if they can do less work than creating a full by-value copy.
So in real codebases, copy-and-swap is valued mainly for:
- correctness
- simplicity
- exception safety
but it is sometimes avoided when performance is more important and the class can support a more direct move 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
This broken pattern can fail on a = a;:
IntArray& operator=(const IntArray& other) {
delete[] data_;
data_ = new int[other.size_];
std::copy(other.data_, other.data_ + other.size_, data_);
size_ = other.size_;
return *this;
}
If other is the same object, other.data_ may refer to memory that was just deleted.
4. Letting swap throw
If swapping can throw exceptions, you lose much of the safety benefit.
Try to make swap cheap and noexcept.
5. Using copy-and-swap when Rule of Zero is better
This is not a bug, but it is a design mistake.
Instead of this:
class BadIdea {
int* data;
// lots of manual special member functions
};
prefer:
#include <vector>
class BetterIdea {
std::vector<int> data;
};
If the standard library can manage the resource for you, use it.
6. Assuming copy-and-swap is always fastest
It is often elegant, but not always optimal.
A by-value parameter may create an extra copy in some cases, especially in pre-C++11 code or for expensive objects.
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 |
By-value assignment vs separate copy/move assignment
| Style | Pros | Cons |
|---|---|---|
operator=(T other) | Simple, unified implementation, works with copy and move | May do extra work compared with specialized move assignment |
operator=(const T&) plus operator=(T&&) | Can be more efficient | More code to write and maintain |
Copy-and-swap vs Rule of Zero
| Technique | Best when |
|---|---|
| Copy-and-swap | You manually manage a resource and need safe assignment |
| Rule of Zero | Your class uses standard RAII members and needs no custom resource logic |
Important takeaway
Copy-and-swap is a tool, not a universal rule. In modern C++, the preferred order is usually:
- Rule of Zero
- Default special members when appropriate
- Custom copy/move logic only when necessary
- Copy-and-swap when it gives a clear safety and simplicity benefit
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
- correct copy constructor
- correct destructor
- correct
swap swapshould ideally benoexcept
Best used when
- class owns raw resources
- you need safe replacement-style assignment
Less needed when
- using
std::string,std::vector, smart pointers - Rule of Zero can be applied
C++11 note
- by-value parameter can use move construction for rvalues
- dedicated move assignment may still be faster in some classes
Watch out for
- forgetting to swap all members
- writing throwing
swap - using manual raw pointers when standard containers would be better
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?
In C++11+, move constructor and move assignment operator may also matter. Copy-and-swap can still be used, but it is now part of a larger design decision around copy and move behavior.
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
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
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++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.