When Does Shallow Copy Break? Mastering Deep vs Shallow Copy in C++
This article explains the difference between shallow and deep copying in C++, shows why the default copy constructor can cause double‑deletion when a class holds pointers, and demonstrates how to implement a proper deep‑copy constructor with clear code examples.
C++ provides two kinds of object copying: shallow copy and deep copy. When an object is assigned using the equals sign, the copy constructor is invoked.
Shallow Copy vs. Deep Copy
If no explicit copy constructor is defined, the compiler generates a default one that performs a shallow copy, copying each member bit‑by‑bit. This works when the class contains only plain data members, but if the class holds pointers, both the original and the copy will point to the same memory. When the objects are destroyed, the same heap block is freed twice, leading to undefined behavior such as memory leaks or crashes.
Simple Shallow‑Copy Example
class A {
public:
A(int _data) : data(_data) {}
A() {}
private:
int data;
};
int main() {
A a(5), b = a; // shallow copy, b.data becomes 5
}In this case the copy is harmless because the class contains only an integer.
Problematic Shallow Copy with Dynamic Memory
class A {
public:
A(int _size) : size(_size) {
data = new int[size];
}
A() {}
~A() { delete[] data; }
private:
int* data;
int size;
};
int main() {
A a(5), b = a; // default shallow copy
}Here the compiler‑generated copy constructor copies the pointer value, so both a and b refer to the same heap block. When b is destroyed it frees the memory, and later a tries to free it again, causing double‑free and undefined behavior.
Implementing a Deep‑Copy Constructor
class A {
public:
A(int _size) : size(_size) {
data = new int[size];
}
// Deep‑copy constructor
A(const A& other) : size(other.size) {
data = new int[size];
std::copy(other.data, other.data + size, data);
}
~A() { delete[] data; }
private:
int* data;
int size;
};
int main() {
A a(5), b = a; // now uses deep copy, no double‑free
}The custom copy constructor allocates a new buffer and copies the contents, ensuring each object manages its own memory.
In summary, shallow copy simply copies member values and is safe only when a class does not own resources such as heap memory, files, or system handles. When a class owns such resources, a deep copy—allocating separate resources for the copy—is required to avoid dangling pointers and double‑deletion.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
