How and When to Make Deep Copies in C++
Classes that allocate resources in their constructor should normally include a copy constructor to create copies of these resources. Allocating a new block of memory and copying the contents of the original into this new block is known as creating a deep copy (as opposed to the default shallow copy). Use the following steps to determine how and when to make deep copies in C++:
Always make a deep copy if the constructor allocates resources.
By default, C++ makes so-called "shallow" member-by-member copies of objects when passing them to functions or as the result of an assignment. You must replace the default shallow copy operators with their deep copy equivalent for any class that allocates resources in the constructor. The most common resource that gets allocated is heap memory that is returned by the new operator.
Always include a destructor for a class that allocates resources.
If you create a constructor that allocates resources, you must create a destructor that restores them. No exceptions.
Always declare the destructor virtual.
A common beginner error is to forget to declare your destructor virtual. The program will run fine until some unsuspecting programmer comes along and inherits from your class. The program still appears to work, but because the destructor in the base class may not be invoked properly, memory leaks from your program like a sieve until it eventually crashes. This problem is difficult to find.
Always include a copy constructor for a class that allocates resources.
The copy constructor creates a proper copy of the current object by allocating memory off of the heap and copying the contents of the source object.
Always override the assignment operator for a class that allocates resources.
Programmers should be discouraged from overriding operators, but the assignment operator is an exception. You should override the assignment operator for any class that allocates resources in the constructor. The assignment operator should do three things:
a. Make sure that the left and right hand object aren't the same object. In other words, make sure that the application programmer didn't write something like (a = a). If they are, do nothing.
b. Invoke the same code as the destructor on the left hand object to return its resources.
c. Invoke the same code as a copy constructor to make a deep copy of the right hand object into the left hand object.
If you can't do all that, create an empty copy constructor and assignment operator and declare them protected to keep other classes from using them.