One of the major difficulties with chaotic software is memory corruption. Allocated memory flows through the system by way of pointer passing. Pointers are being passed among modules and threads. In a chaotic software system this will result in two major difficulties.
- Memory leaks. This happens when memory is never freed and will, over time, bring the application down when its consumption of memory gets out of hand.
- Premature deletion. When ownership of a memory pointer is not clear, it may result in memory being accessed after it was already deleted, resulting in immediate catastrophic failure.
Fortunately, C++ offers a solution to both problems. C++ allows you to control all points of object creation, destruction, copy, and assignment. You can leverage that control to develop a form of garbage collection called reference counting. The basic idea is to transfer the object destruction responsibility from the client code to the object itself. The object keeps track of the current number of references to it and destroys itself when the reference count reaches zero. In other words, the object destroys itself when nobody is using it any longer. With the vast majority of software defects being traced back to memory corruption, reference counting is a very important technique in the C++ arsenal.
The relationship between reference counting and execution speed is context-sensitive. It depends on a few factors:
- What is the magnitude of resource consumption by the target object? If the target object uses gigantic amounts of memory, for example, a failure to conserve memory will push the limits on available memory and lead to dramatic performance loss in the form of cache misses and page faults.
- How expensive is it to allocate (and deallocate) the resource used by the target object? This is different from the previous factor. An object such as BigInt will typically consume a small amount of storage and is unlikely to deplete available memory. However, allocating even one byte from the heap will cost you hundreds of instructions. The same goes for deallocating a single byte.
- How many objects are likely to share a single instance of the target object? Sharing is increased by the use of the assignment operator and copy constructor.
- How often do we create (destroy) first (last) references to the target object? Creating a brand-new reference-counted object using a constructor other than the copy constructor will create a first reference to the target object. This is expensive. It has more overhead in comparison to creating the target object. The same argument applies to the removal of a last reference.
So in summary these are reasons why to use reference counting pointers:
- The target object is a large resource consumer.
- The resource in question is expensive to allocate and free.
- A high degree of sharing; the reference count is likely to be high due to the use of the assignment operator and copy constructor.
- The creation or destruction of a reference is relatively cheap.
If you reverse these items, you start leaning towards skipping reference counting in favor of the plain uncounted object