Strict mode for C++ |
The C++ standard has auto_ptr, a single-owner smart pointer.
You can't copy an auto_ptr, since that would result in two pointers owning the same object. This has several consequences, all bad. STL collections of auto_ptr don't work, because STL collections assume that collection elements are copyable. It's possible to write collections for uncopyable objects, but the STL doesn't work that way.
The current semantics of auto_ptr require that assigning one auto_ptr to another clears the source object, the one on the right hand side of the assignment. These are very nonstandard semantics for an assignment operator. But the only other choice would have been to disallow assignment. It took three major revisions to come up with these, which are at best unsatisfying. Few are happy with this outcome.
There's a substantial literature on smart pointers Many implementations have been tried. All run into problems.
An AT&T effort which included the development of a "smart pointer" template library. This particular library is thread-safe.
The DjVu developers tried to support both reference-counted and non reference-counted pointers in an interoperable fashion. This was done at run-time; pointers started out in "manual" (non reference-counted) mode and switched to "automatic" (reference-counted) mode when assigned to a reference-counted pointer. This could result in wierd semantics and accidental deallocation. As the authors wrote:
Safety considerations --- As explained above, a GPEnabled object switches to automatic mode as soon as it becomes referenced by a smart-pointer. There is no way to switch the object back to manual mode. Suppose that you have decided to only use regular pointers with a particular GPEnabled object. You therefore plan to destroy the object explicitly when you no longer need it. When you pass a regular pointer to this object as argument to a function, you really need to be certain that the function implementation will not assign this pointer to a smart-pointer. Doing so would indeed destroy the object as soon as the function returns. The bad news is that the fact that a function assigns a pointer argument to a smart-pointer does not necessarily appear in the function prototype. Such a behavior must be documented with the function public interface. As a convention, we usually write such functions with smart-pointer arguments instead of a regular pointer arguments. This is not enough to catch the error at compile time, but this is a simple way to document such a behavior. We still believe that this is a small problem in regard to the benefits of the smart-pointer. But one has to be aware of its existence.
This sort of thing is why "strict mode" requires some compiler support.
The ill-fated Taligent library, once a major Apple project, addressed the safe pointer issue with the following primitves.
TAliasTo<> -- The pointer does not own the object.
TInstanceOf<> -- The pointer owns the object, permanently.
TOnlyPointerTo<> -- The pointer owns the object, but may transfer ownership to another pointer.
Taligent assumed careful front-end design of data structures, with binding decisions made early. This may be overly constraining.
There are many other smart pointer implementations. All run into limitations of C++ that make them either inefficient or unsafe. If this problem could be solved within the C++ framwork, it would have been.
One big decision on smart pointers is whether they should be thread-safe. Thread safety requires locking, or at minimum, atomic increment and decrement operations. On many platforms, locking is slow, often very slow compared to a simple increment. This issue needs to be thought through when and if the next revision of C++ addresses synchronization generally.
July 2, 2001