scoped_ptr
for automatic destruction:Using normal pointers | Using scoped_ptr |
Collapse void Sample1_Plain() { CSample * pSample(new CSample); if (!pSample->Query() ) // just some function... { delete pSample; return; } pSample->Use(); delete pSample; } | Collapse #include "boost/smart_ptr.h" void Sample1_ScopedPtr() { boost::scoped_ptr<CSample> samplePtr(new CSample); if (!samplePtr->Query() ) // just some function... return; samplePtr->Use(); } |
The boost::shared_ptr
implementation has some important features that make it stand out from other implementations:
shared_ptr<T>
works with an incomplete type:When declaring or using a
shared_ptr<T>
,T
may be an "incomplete type". E.g., you do only a forward declaration usingclass T;
. But do not yet define howT
really looks like. Only where you dereference the pointer, the compiler needs to know "everything".shared_ptr<T>
works with any type:There are virtually no requirements towards
T
(such as deriving from a base class).shared_ptr<T>
supports a custom deleterSo you can store objects that need a different cleanup than
delete p
. For more information, see the boost documentation.- Implicit conversion:
If a type
U *
can be implicitly converted toT *
(e.g., becauseT
is base class ofU
), ashared_ptr<U>
can also be converted toshared_ptr<T>
implicitly. shared_ptr
is thread safe(This is a design choice rather than an advantage, however, it is a necessity in multithreaded programs, and the overhead is low.)
Using shared_ptr in containers
Many container classes, including the STL containers, require copy operations (e.g., when inserting an existing element into a list, vector, or container). However, when this copy operations are expensive (or are even unavailable), the typical solution is to use a container of pointers:
Collapsestd::vector<CMyLargeClass *> vec; vec.push_back( new CMyLargeClass("bigString") );
However, this throws the task of memory management back to the caller. We can, however, use a
shared_ptr
:Collapsetypedef boost::shared_ptr<CMyLargeClass> CMyLargeClassPtr; std::vector<CMyLargeClassPtr> vec; vec.push_back( CMyLargeClassPtr(new CMyLargeClass("bigString")) );
Very similar, but now, the elements get destroyed automatically when the vector is destroyed - unless, of course, there's another smart pointer still holding a reference.
Rules : shared_ptr usage
- When creating a smart pointer, you explicitly have to write
..._ptr<T> myPtr(new T)
- You cannot assign a
T *
to a smart pointer - You cannot even write
ptr=NULL
. Useptr.reset()
for that. - To retrieve the raw pointer, use
ptr.get()
. Of course, you must not delete this pointer, or use it after the smart pointer it comes from is destroyed, reset or reassigned. Useget()
only when you have to pass the pointer to a function that expects a raw pointer. - You cannot pass a
T *
to a function that expects a_ptr<T>
directly. You have to construct a smart pointer explicitly, which also makes it clear that you transfer ownership of the raw pointer to the smart pointer. (See also Rule 3.) - There is no generic way to find the smart pointer that "holds" a given raw pointer. However, the boost: smart pointer programming techniques illustrate solutions for many common cases.
- No circular references - If you have two objects referencing each other through a reference counting pointer, they are never deleted. boost provides
weak_ptr
to break such cycles (see below).
- When creating a smart pointer, you explicitly have to write
No comments:
Post a Comment