auto_ptr Is Unusual



Item 43. auto_ptr Is Unusual

Whenever one discusses RAII, it's necessary to discuss auto_ptr. This is always a task. It's not that we're ashamed of auto_ptr, mind you, but it's kind of like explaining your brother to strangers; he's a superlative person, but you have to be in the right frame of mind to appreciate that. And there's no denying that both your brother and auto_ptr have a different worldview from the typical person or object, respectively.

As we discussed in RAII [40, 139], the use of resource handles is a pervasively employed technique in C++ programming, so the standard library supplies a resource handle template that serves many resource handle needs: auto_ptr. The auto_ptr class template is used to generate smart pointers (see Smart Pointers [42, 145]) that know how to clean up after themselves.

using std::auto_ptr; // see Namespaces [23, 81]
auto_ptr<Shape> aShape( new Circle );
aShape->draw(); // draw a circle
(*aShape).draw(); // draw it again

Like all well-designed smart pointers, auto_ptr overloads operator -> and operator * so that you can usually pretend you're dealing with a built-in pointer. There are many nice things about auto_ptr. First, it's very efficient. You're not likely to get better performance with a hand-coded solution that uses a built-in pointer. Second, when an auto_ptr goes out of scope, its destructor will free whatever it's pointing to, just as our hand-coded resource handle did. In the code fragment above, the Circle object to which aShape refers will be (effectively) garbage collected.

A third nice thing about auto_ptr is that it behaves like a built-in pointer with respect to conversions:

auto_ptr<Circle> aCircle( new Circle );
aShape = aCircle;

Through its clever use of template member functions (see Member Templates [50, 173]) one auto_ptr can be copied to another if the corresponding built-in pointers could. In the code above, an auto_ptr<Circle> can be assigned to an auto_ptr<Shape> because a Circle * can be assigned to a Shape * (assuming that Shape is a public base class of Circle).

Where auto_ptr differs from the typical smart pointer (or typical object, for that matter) is in its copy operations. For a typical class, the copy operations (see Copy Operations [13, 45]) will not affect the source of the copy. In other words, if T is some type

T a;
T b( a ); // copy construction of b with a
a = b; // assignment from b to a

then when b is initialized with a, the value of a is unaffected, and when b is assigned to a, the value of b is unaffected. Not so with auto_ptr! When we assigned aCircle to aShape above, both source and target of the assignment were affected. If aShape was non-null, whatever it referred to was deleted and replaced with what aCircle pointed to. In addition, aCircle was set to null. Assignment and initialization of auto_ptrs are not really copy operations; they are operations that transfer control of the underlying object from one auto_ptr to another. One can think of the right argument of an assignment or initialization as a "source" and the left argument as a "sink." Control of the underlying object is passed from source to sink. This is a good property in a resource handle.

However, one should avoid the use of auto_ptrs in two common situations. First, they should never be used as container elements. Container elements are often copied around within a container, and the container will assume that its elements obey the usual, non-auto_ptr copy semantics. Feel free to use a smart pointer as a container element, just as long as it's not an auto_ptr. Second, an auto_ptr should refer to a single element, not an array. The reason is that when the object to which the auto_ptr refers is deleted, it will be deleted using operator delete, not array delete. If the auto_ptr refers to an array, the wrong deletion operator will be called (see Array Allocation [37, 127]).

vector< auto_ptr<Shape> > shapes; // likely error, bad idea   
auto_ptr<int> ints( new int[32] ); // bad idea, no error (yet)

Generally, a standard vector or string is a reasonable alternative to an auto_ptr to an array.