C++ shallow copy and deep copy
Copying an object means creating a new object from an existing object.
For simple classes, the compiler-generated copy is usually fine.
For classes that own dynamic memory, the compiler-generated copy can be dangerous because it performs a shallow copy.
Shallow copy
A shallow copy copies the member values exactly.
If a member is a pointer, only the pointer address is copied. The data behind the pointer is not copied.
That means two objects can point to the same memory.
If data points to heap memory, a shallow copy creates this situation:
Both objects point to the same int.
Problem: no copy constructor implementation
In this example, the class owns memory allocated with new.
But it does not implement a copy constructor.
The compiler-generated copy constructor copies data_ as an address.
So both objects contain the same pointer value.
This creates two problems:
- changing
balso changesa - when both objects are destroyed, both destructors call
deleteon the same pointer
The second problem is a double delete, which is undefined behavior. The program may crash, appear to work, or fail later.
Deep copy
A deep copy creates new owned memory for the new object.
The pointer address is different, but the value is copied.
Now each object owns its own memory.
Fix: implement a copy constructor
The important line is:
This allocates a new int and copies the value from other.
Now a and b are independent objects.
Copy constructor signature
The copy constructor usually looks like this:
Example:
Use const ClassName& because:
constmeans the source object will not be modified&avoids copying the source object again
Important: copy assignment is a separate function
This calls the copy constructor:
This calls the copy assignment operator:
If a class owns raw memory and implements a destructor and copy constructor, it usually also needs a copy assignment operator.
This is called the Rule of Three.
Modern C++ note
Prefer standard library ownership types instead of raw new and delete.
For one value, store the value directly:
For dynamic arrays, prefer std::vector.
For exclusive heap ownership, prefer std::unique_ptr.
Manual deep copy is still important to understand because it explains why copy constructors, destructors, ownership, and the Rule of Three exist.