Deep vs. Shallow Copy in C++: Why Proper Copy Constructors Matter
This guide explains the difference between shallow and deep copying in C++, shows how the compiler‑generated copy constructor performs a shallow copy, demonstrates the pitfalls with pointer members, and provides a custom copy constructor example that safely implements deep copying.
Difference Between Shallow and Deep Copy
In C++, copying an object can be performed either as a shallow copy or a deep copy. When the assignment operator or copy constructor is invoked without an explicit definition, the compiler generates a default copy constructor that performs a shallow copy, simply copying each member bit‑by‑bit.
Shallow copy works fine when a class contains only plain data members. However, if the class holds pointers to dynamically allocated memory (or other resources such as file handles), a shallow copy will duplicate the pointer values, causing multiple objects to reference the same resource. When both objects are destroyed, the resource is released twice, leading to undefined behavior, memory leaks, or crashes.
Shallow Copy Example
class A {
public:
A(int _data) : data(_data) {}
A() {}
private:
int data;
};
int main() {
A a(5), b = a; // shallow copy of data member
}In this example, b = a copies the integer member, which is safe because no dynamic resources are involved.
Problem When Pointers Are Involved
class A {
public:
A(int _size) : size(_size) {
data = new int[size]; // allocate dynamic memory
}
A() {}
~A() {
delete [] data; // release resource
}
private:
int* data;
int size;
};
int main() {
A a(5), b = a; // default shallow copy
}The generated copy constructor copies the pointer data and the size value. After the assignment, both a and b point to the same heap block. When b is destroyed, it deletes the memory; subsequently, a attempts to delete the same memory again, causing double‑free errors.
Implementing a Deep Copy
To avoid the above issue, a class must define its own copy constructor that allocates a new resource and copies the contents, i.e., a deep copy.
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];
// copy the actual data if needed
}
~A() {
delete [] data;
}
private:
int* data;
int size;
};
int main() {
A a(5), b = a; // now uses deep copy, safe
}Here the custom copy constructor allocates its own memory block and copies the size, ensuring that a and b manage independent resources.
Conclusion
When a class contains pointers or other external resources, the default shallow copy is insufficient and can lead to undefined behavior. Implementing a deep copy constructor (or using smart pointers/RAII) ensures each object owns its own copy of the resource, preventing double deletions and memory leaks.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
