ONLamp.com
oreilly.comSafari Books Online.Conferences.

advertisement


Smart Pointers in C++
Pages: 1, 2, 3, 4, 5

The RAII Model

RAII (resource acquisition is initialization) is a programming idiom intended to make code more robust. This model is restricted to object-oriented programming languages that have a predictable object destruction flow: where the developer could deduce, if he wanted to, the exact place at which an object's destructor is called. C++ is one such language, assuming you use no garbage collector.



The basic principle behind RAII is to wrap dynamic resources--those that are allocated at some point and deallocated some time later--inside thin classes that manage them in a transparent way. These classes have several characteristics:

  • Their constructor allocates the resource and attaches it to the constructed instance. If the resource cannot be allocated, the construction aborts and throws an exception. Therefore all initialized objects have a valid resource.

  • Their destructor deallocates the resource as soon as possible. If the resource is shared among multiple instances, the wrapper class will release it only when the last instance disappears. A typical way to achieve this behavior is by using a reference counter.

  • They are extremely lightweight. Generally speaking, all they contain is a reference to the dynamic object they manage and some inline methods--often in the form of overloaded operators--to access it.

  • Wrapping resource acquisition and release within a class is good design. The caller neither needs nor wants to deal with resource-specific details.

By using RAII-modeled classes, the developer need not care about explicitly releasing the acquired resources: they will be freed automatically when the instance that manages them goes out of scope. It is important to note that these instances are almost always local variables (they live in the stack or within another object as an attribute); placing them in the heap (thus making them dynamic) makes no sense and could defeat the whole idea behind RAII.

As an example, consider the std::ofstream class, modeled using RAII. This class has a redundant close method, provided only for cleanliness so as to allow the developer to explicitly tell where the file ceases to be open. If this function never gets called, the file will close as soon as the class's instance goes out of scope. For example:

int
read_something(void)
{
    int value;

    std::ifstream f("test.tmp");
    if (!f) {
        // First exit point
        throw no_such_file_exception("The file test.tmp does " +
                                     "not exist");
    }

    f >> value;
    if (value == 0) {
        // Second exit point
        throw invalid_format_exception("The file test.tmp is " +
                                       "corrupt");
    }

    // Third exit point
    return value;
}

The read_something function has at least three exit points, clearly marked in the code using comments. Now notice that there is no difference in f's handling in them. It does not matter whether the object was initialized, or if the code exited prematurely or successfully. The code simply ignores that the object exists, which is possible because std::ifstream's destructor closes the file. Otherwise, the code shown could leak an open file each time it took the second exit point.

For more information on the RAII programming idiom, I suggest you read The RAII Programming Idiom by Jon Hanna; it explains what RAII is in great detail and shows examples in both C++ and VB6.

Smart Pointers

A smart pointer is an RAII-modeled class that holds and manages a dynamically allocated chunk of memory. The exact behavior of the smart pointer is defined by its implementation, not by the fact that it is a smart pointer. In other words, a smart pointer is "smarter" than a raw pointer because it does some tasks automatically on behalf of the user; the tasks it does, however, depend on its specification.

Smart pointers are also helpful to specify how a pointer behaves based solely on notation. This is very useful when defining an API, because pointers in function signatures typically lead to confusion: Is the pointer an output parameter? Who is in charge of allocating the memory? Who has to release it? Using a smart pointer automatically answers some--if not all--of these questions.

The standard C++ library has a simple smart pointer, useful in many simple situations. However, due to those limitations, third-party libraries provide a wide variety of smart pointers with different features.

Pages: 1, 2, 3, 4, 5

Next Pagearrow





Sponsored by: