- Smart Pointers 101
- The Deal
- Storage of Smart Pointers
- Smart Pointer Member Functions
- Ownership-Handling Strategies
- The Address-of Operator
- Implicit Conversion to Raw Pointer Types
- Equality and Inequality
- Ordering Comparisons
- Checking and Error Reporting
- Smart Pointers to const and const Smart Pointers
- Arrays
- Smart Pointers and Multithreading
- Putting It All Together
- Summary
7.15 Summary
Congratulations! You have just read one of the longest, wildest chapters of this book—an effort that we hope has paid off. Now you know a lot of things about smart pointers and are equipped with a pretty comprehensive and configurable SmartPtr class template.
Smart pointers imitate built-in pointers in syntax and semantics. In addition, they perform a host of tasks that built-in pointers cannot. These tasks might include ownership management and checking against invalid values.
Smart pointer concepts go beyond actual pointer behavior; they can be generalized into smart resources, such as monikers (handles that don't have pointer syntax, yet resemble pointer behavior in the way they enable resource access).
Because they nicely automate things that are very hard to manage by hand, smart pointers are an essential ingredient of successful, robust applications. As small as they are, they can make the difference between a successful project and a failure—or, more often, between a correct program and one that leaks resources like a sieve.
That's why a smart pointer implementer should invest as much attention and effort in this task as possible; the investment is likely to pay in the long term. Similarly, smart pointer users should understand the conventions that smart pointers establish and use them in accordance with those conventions.
The presented implementation of smart pointers focuses on decomposing the areas of functionality into independent policies that the main class template SmartPtr mixes and matches. This is possible because each policy implements a well-defined interface.
7.16 SmartPtr Quick Facts
SmartPtr declaration:
template < typename T, template <class> class OwnershipPolicy = RefCounted, class ConversionPolicy = DisallowConversion, template <class> class CheckingPolicy = AssertCheck, template <class> class StoragePolicy = DefaultSPStorage > class SmartPtr;
T is the type to which SmartPtr points. T can be a primitive type or a user-defined type. The void type is allowed.
For the remaining class template parameters (OwnershipPolicy, ConversionPolicy, CheckingPolicy, and StoragePolicy), you can implement your own policies or choose from the defaults mentioned in Sections 7.14.1 through 7.14.4.
OwnershipPolicy controls the ownership management strategy. You can select from the predefined classes DeepCopy, RefCounted, RefCountedMT, COMRefCounted, RefLinked, DestructiveCopy, and NoCopy, described in Section 7.14.2.
ConversionPolicy controls whether implicit conversion to the pointee type is allowed. The default is to forbid implicit conversion. Either way, you can still access the pointee object by calling GetImpl. You can use the AllowConversion and DisallowConversion implementations (Section 7.14.3).
CheckingPolicy defines the error checking strategy. The defaults provided are AssertCheck, AssertCheckStrict, RejectNullStatic, RejectNull, RejectNullStrict, and NoCheck (Section 7.14.4).
StoragePolicy defines the details of how the pointee object is stored and accessed. The default is DefaultSPStorage, which, when instantiated with a type T, defines the reference type as T&, the stored type as T*, and the type returned from operator-> as T* again. Other storage types defined by Loki are ArrayStorage, LockedStorage, and HeapStorage (Section 7.14.1).