A great feature of C++ is that shallow copy constructors and assignment operators are done for you. If you have a class with simple types, you automatically get the ability to construct a clone of any existing object, or assign any one object to another.

However, if you have member variables that are involved in any kind of dynamic allocations, you’re going to need to override the default copy/assignment functions with your own “deep copy” versions.  This leads me to the characteristic I find most annoying about C++: if you decide to write your own copy constructor or assignment operator, it’s an all-or-nothing affair – you lose the default version when you create your own. There can only be one, after all. But this means that if you have a class with dozens of constantly changing member variables, you have a real maintenance headache keeping the copy constructor and assignment operator up to date. You should use a common function for them (or call one from the other), but you still have to maintain the member variables in that function. This stinks – it flies in the face of the most basic maintenance-friendly design philosophy: encapsulate similar functionality in one place.

The solution is two split the class into two subclasses. At first this sounds severe, and perhaps it is in a class with only a handful of member variables. But I propose that it is essential in the situation where you are dealing with a class that has both a large number of simple member variables alongside any dynamically allocated members requiring deep copying.

I suggest the following strategy when the above criteria are met:

  • for original class foo, split into…
    • foo_shallow – a base class that uses the built-in shallow copy/assignment functions; the ONLY purpose of this class is to provide those built-in functions, and there should be nothing in it but simple member variables
    • foo – a derived class with deep copy copy/assignment functions; these functions call the built-in base class versions
  • all of the functionality can stay in foo, where all variables are available

Fun fun, party on!

Leave a Reply