If there was any one library that I could not live without, it would be Boost's shared_ptr
library. Used in combination with RAII, it simply prevents resource leaks. Yes, really. And the basic usage is simple. What shared pointers do is maintain an internal reference count to the number of instances referencing a particular resource. When an instance shows the reference count go to zero it releases the resource. By far the most common usage is memory. Let's take a look at that.
In many cases, the shared_ptr can then be used just like a naked pointer:
- de-reference it with
*ptr
- access members with
ptr->mem
- pass it to functions expecting a naked pointer of the same type using the
get()
operator
Where you need to pay more attention to shared_ptr
is:
- Casting pointers is done with
static_pointer_cast
,dynamic_pointer_cast
andconst_pointer_cast
instead ofstatic_cast
,dynamic_cast
andconst_cast
; - When using the
shared_ptr
as a deduced template parameter
When you need a naked pointer, use the T* shared_ptr::get()
member function, which returns the underlying naked pointer.
Sometimes you want to reset a shared_ptr
to an uninitialized state. To do so, use the reset()
member function. If you find yourself using reset()
a lot, consider whether the calling structure for your program is appropriate.
There is a separate header to manage array allocations via new[]
, but I recommend against it. Arrays are better handled in other ways, e.g. either via std::vector
or boost::array
.
There are other kinds of resources to manage. boost::shared_ptr
can also handle those so long as:
- The type has pointer semantics, meaning that it can be dereferenced with
*
, members can be accessed with ->, and that copies of the "pointer" are shallow copies. - There is a function or function object that accepts the type as an argument and releases it.
- There is a second, optional construction argument which is the function or function object called for destruction.
It's more easily understood with an example.
That class could be used like this:
#include #include #include "ExSafeFILE.hpp" typedef std::vector IntVec; void writeToFile(const std::string& fileName) { static const size_t N=64; int p[N] = {1,2,4,8,16,32,64,128,256}; ExSafeFILE fileHandle( fopen("test.txt","wb") ); size_t elementSize = sizeof(int); fwrite(p,elementSize,N,fileHandle); } // end writeToFile()
In keeping with the STL containers, boost::shared_ptr
defines internal typedefs that are useful:
value_type
- the type of the parameterizing typeT
inboost::shared_ptr
pointer
- the type of
T*
Note that the shared_ptr
from Boost has been accepted into C++11. While both Visual Studio 2010 and g++ 4.4 have implementations of shared_ptr
that I have tried, I continue to use boost::shared_ptr
because I find it has better error messages and is more robust. Be careful about importing via using namespace boost;
in conjunction with boost::shared_ptr
and a C++11 compiler because you will get namespace collisions with std::shared_ptr
.