One problem with all programming languages that support the notion of pointers is the management of the memory associated with a pointer. A large computer program is usually comprised of several libraries. A library presents an application programming interface (API) to the user and hides the implementation details (e.g., internal data structures, memory management, ...). Such an API consists of a set of function and struct declarations for the case of the C programming language, or a set of concrete and interface classes for the case of an object-oriented designed library written in the C++ programming language. In any case, if a library performs some sort of memory management, two important questions arise
C++ lacks a built in garbage collector. Therefore, a simple reference counting algorithm suggested in [2] was implemented in the WAFER-STATE-SERVER. The implementation uses the template polymorphism mechanism to provide type independence. This reference counting technique is referred to as the handle class throughout this work. A handle consists of two pointers. One points to the data to manage (the representation pointer), the other is a pointer to an integer variable holding a reference counter. Fig. 3.19
Handles are always created on the runtime stack of the program never on the free store. Thus, when the handle loses its scope the destructor automatically disassociates the handle from the object and deallocates memory occupied by the object if necessary (last handle). This makes an explicit deallocation of the handled object unnecessary in most cases. A notable exception is the implementation of the WSS Writer, where the destructors of the handled objects are used to finish (close) a section. In this case an explicit assignment of a handle to the null pointer is used to force a disassociation and a call of the appropriate destructor.
The handle class overloads the operators *, ->, < and > to ensure full syntax compatibility to a real pointer. Access to the representation pointer is checked and an exception will be raised in case of a detected null pointer dereferencing. Note, that a handle imposes the memory overhead of one pointer and one integer variable compared to a non-handled counterpart. Therefore, the use of handles for variables that consume only small memory amounts like integers or doubles is not advised.
The performance overhead introduced by a handle depends on the compilation of the program. There is a switch to turn run time access checks of the representation pointer on or off. For optimized compiled programs that are compiled with the GNU compiler, all methods of the handle template are inlined and the access checks to the pointer are automatically turned off. The overhead remaining in that case is the call of the new operator for the integer variable and the overhead for the memory management of the underlying operating system. Parts of that overhead are eliminated by providing a specialized new operator for integers. This operator also reduces the memory overhead of the reference counter from a minimum (given by the operating system) of bytes to bytes on a bit architecture. The operator is implemented using a memory pool similar to the one described in [2]. Note that all handle operations (assignment, copying, ...) must be guaranteed to be atomic or the result is undefined. Therefore, special care must be taken in multi threaded applications to ensure thread safety.
2003-03-27