In C++, copying an object might look simple, but it comes in two forms: shallow copy and deep copy. These approaches directly affect program correctness, memory safety, and performance.
What is Copying in C++? #
Copying means creating a new object by duplicating the values of an existing one. The difference between shallow and deep copy becomes critical when dealing with pointers and dynamically allocated memory.
Shallow Copy: Surface-Level Duplication #
A shallow copy only duplicates member values, including pointers. As a result, multiple objects may share the same memory location—leading to unintended side effects.
// Example: Shallow Copy
#include <iostream>
class ShallowCopyExample {
public:
int* data;
ShallowCopyExample(const ShallowCopyExample& other) {
// Shallow copy
data = other.data;
}
void DisplayData() {
std::cout << "Data: " << *data << std::endl;
}
};
int main() {
ShallowCopyExample obj1;
obj1.data = new int(42);
ShallowCopyExample obj2 = obj1; // Shallow copy
obj1.DisplayData(); // Output: Data: 42
obj2.DisplayData(); // Output: Data: 42
*obj1.data = 99; // Change through obj1
obj1.DisplayData(); // Output: Data: 99
obj2.DisplayData(); // Output: Data: 99 (unexpected!)
delete obj1.data; // Leaves obj2 with a dangling pointer
return 0;
}
With shallow copy, objects share the same pointer. Modifying one object changes the other, and deleting memory in one can break the other.
Deep Copy: Independent Cloning #
A deep copy duplicates both object members and the memory pointed to by pointers. Each object maintains its own independent copy of the data.
// Example: Deep Copy
#include <iostream>
class DeepCopyExample {
public:
int* data;
DeepCopyExample(const DeepCopyExample& other) {
// Deep copy
data = new int(*other.data);
}
~DeepCopyExample() {
// Free allocated memory
delete data;
}
void DisplayData() {
std::cout << "Data: " << *data << std::endl;
}
};
int main() {
DeepCopyExample obj1;
obj1.data = new int(42);
DeepCopyExample obj2 = obj1; // Deep copy
obj1.DisplayData(); // Output: Data: 42
obj2.DisplayData(); // Output: Data: 42
*obj1.data = 99;
obj1.DisplayData(); // Output: Data: 99
obj2.DisplayData(); // Output: Data: 42 (independent copy)
delete obj1.data;
return 0;
}
With deep copy, objects are independent—changes to one do not affect the other.
Choosing Between Shallow and Deep Copy #
-
Use shallow copy if:
- Your class does not manage dynamic memory.
- Shared access to the same resource is acceptable.
-
Use deep copy if:
- Your class manages dynamically allocated memory.
- Each object should maintain its own copy of data.
- You want to avoid dangling pointer issues.
Memory Management Considerations #
Deep copy requires careful cleanup to prevent leaks. Always implement a proper destructor, and consider the Rule of Three/Five (copy constructor, copy assignment operator, destructor, and possibly move semantics).
Quick Comparison Table #
Feature | Shallow Copy | Deep Copy |
---|---|---|
What is copied | Member values only (including raw pointers) | Member values and the memory they point to |
Memory usage | Lower | Higher (allocates new memory) |
Object independence | Not independent—changes affect both | Independent—changes do not affect each other |
Risk | Dangling pointers, double deletion | Higher cost but safer |
When to use | When no dynamic memory is managed, or shared data is intentional | When objects must own their own memory |
Conclusion #
- Shallow copy is lightweight but risky when pointers are involved.
- Deep copy ensures data independence, though it requires more memory and processing.
By understanding both approaches, you can choose the right strategy for safe, efficient C++ programming.