There are a lot of mechanisms through which programmers can make their code cleaner, preserve memory, and still harness the power of the programming language in use. Such mechanisms almost always have demerits that are coupled with their merits. One such mechanism, used primarily in intermediate-level programming languages such as C++, is the Use of Smart Pointers which helps with automatic garbage collection and/or bounds checking. Smart pointers can save a programmer’s time and could further prevent a program from crashing or corrupting files on the system on which it is run due to memory leak or bounds wrapping/overwriting. A smart pointer is an abstract data type that simulates an ordinary pointer but still provides extra features mostly centered around memory management. This article will be based upon the use of pointers in C++.
A pointer in C/C++ is used to store the memory address of its pointee (memory address of an object — an instance of a class).
Book* myPointer = new Book(); // myPointer could be an instance of the Book class or any subclass of the
// Book class
Every time we allocate memory on the heap (through the use of pointers), we must remember to deallocate/reallocate the memory on the heap in order to make the memory available again for use by other parts of the program. This can be done by using the delete keyword like this:
delete myPointer; // or delete[] myPointers where myPointers be an array
Failure to delete a pointer or pointers can result in memory leak (where the memory allocated from the free store wouldn’t be available for use by other parts of the program). So a programmer must always keep track of his pointers and try to curb the risk of letting pointers go out of scope without deallocating the memory used by corresponding pointees. It is hard, especially in a complicated/verbose source, for the programmer to keep track of all pointers used and try to delete them. Smart pointers simplify this task.
There are different ways to implement smart pointers. Some of which are through the use of reference counting and/or operator overloading. However, in C++, smart pointers may be implemented as a template class that mimics, by means of operator overloading, the behavior of traditional (raw) pointers, (e.g.: dereferencing, assignment) while providing additional memory management algorithms. An example pointer implementation is the BOOST library, a high-quality open-source library, that has been considered for inclusion into the standard C++ library. This library provides the following pointer implementations:
shared_ptr<T> |
pointer to T" using a reference count to determine when the object is no longer needed. shared_ptr is the generic, most versatile smart pointer offered by boost. |
scoped_ptr<T> |
a pointer automatically deleted when it goes out of scope. No assignment possible, but no performance penalties compared to “raw” pointers |
intrusive_ptr<T> |
another reference counting pointer. It provides better performance than shared_ptr , but requires the type T to provide its own reference counting mechanism. |
weak_ptr<T> |
a weak pointer, working in conjunction with shared_ptr to avoid circular references |
shared_array<T> |
like shared_ptr , but access syntax is for an Array of T |
scoped_array<T> |
like scoped_ptr , but access syntax is for an Array of T |
I can’t go through all these implementations in this article. For more details, check out the online docs. of the C++ BOOST library. In addition, the C++ standard library provides a class template called auto_ptr
(declared in the memory header file) that provides some basic supplementary memory management capabilities for C++ raw pointers.
Smart pointers do not only help in memory management but also help support intentional programming (when the programmer code reflects his intention — his original conception when he was about to start coding). For example, if the programmer wanted to make a pointer function (which is, by the way, useful for making functions polymorphic) like this: Book* myPointerFunction();
. If he were to use raw pointers, he would have to figure out how he would delete myPointerFunction()
. On the other hand, if he had access to smart pointers he wouldn’t have to worry about deleting myPointerFunction();
, thus more readily portraying the programmer’s intention without side effects.
In programming languages like Java, C#, VB, and Python, the deleting of “pointers” (there are no explicit pointers) are done through their respective garbage collection algorithms and mechanisms. So programmers wouldn’t have to worry unnecessarily about deleting pointers. Even these programming language have different garbage collection schemes depending on the implementation. The standard C implementation (CPython) uses reference counting to detect inaccessible objects, and a separate mechanism to collect reference cycles, periodically executing a cycle detection algorithm which looks for inaccessible cycles and deletes the objects involved. The gc module provides functions to force garbage collection, obtain debugging statistics, and tune the collector’s parameters. On the other hand, Jython relies on the Java runtime so the JVM’s garbage collector is used. The same applies to IronPython, which uses the CLR garbage collector. This difference can cause some subtle porting problems if your Python code depends on the behavior of the reference counting implementation.
A major demerit in using smart pointers is that the encapsulating nature of smart pointers could cause problems when pointers are used with a “rigid” frameworks that only accept raw pointers. This can be very difficult to handle unless the smart pointer implementation, in this case, has an implicit conversion scheme to its raw pointer type (a dangerous thing indeed).
I must say that the disadvantages of using pointers is trivial! On the other hand, they could ultimately save the programmer’s code-writing and debugging time and improve the quality of the software in which they are used. Overall, smart pointers are very useful if they are needed (that is, when there is a somewhat heavy/tangled/non-explicit use of pointers) but must be used wisely and carefully.