std::tr1::shared_ptr tutorial
The C++ TR1 additions contain an extremely useful smart pointer: std::tr1::shared_ptr
. Used properly, it allows creating efficient and safe C++ code without the risk of memory leaks. Point in case: I have a personal project with 10k + LoC without a single delete call.
How to get it, and what it is
std::tr1::shared_ptr
is part of the TR1 additions to the C++ STL. With GCC, it is available either through #include <tr1/memory>
(GCC 4.1) or #include <memory>
(GCC 4.3), the latter form works also on Windows (with VS2008 SP1). If you want to be portable, try Boost, which uses the vendor-provided solution if possible and falls back to a custom one if no vendor solution was found. To use this, just include <boost/tr1/memory.hpp>
Basically, the shared pointer is a reference counted pointer. The references are counted using atomic instructions, so it is (mostly) thread-safe. Exception: If you pass the shared pointer by reference, and it is modified then by two threads, you’ll run into problems, so copy it!
Usage examples
Let us take a look at several usage examples.
Deleting an array
An array can be deleted by providing a custom array deleter.
template <typename T>
class ArrayDeleter
{
public:
void operator () (T* d) const
{
delete [] d;
}
};
int main ()
{
// Usage
std::tr1::shared_ptr<double> array (new double [256], ArrayDeleter<double> ());
}
or, if you have Boost and included <boost/smart_ptr.hpp>
and you need a temporary array
boost::scoped_array<double> array (new double [256]);
scoped_array is noncopyable, which makes it perfect for local buffers.
Casting
It is possible to cast shared pointers using std::tr1::dynamic_pointer_cast
and std::tr1::static_pointer_cast
.
class Base
{
};
class Derived : public Base
{
};
int main ()
{
std::tr1::shared_ptr<Base> base (new Derived ());
// Static downcast
std::tr1::shared_ptr<Derived> derived = std::tr1::static_pointer_cast<Derived> (base);
}
Custom reference counting
If your class has custom reference counting (COM, anyone?), you can still use shared pointers for it.
class CustomReferenceCounted
{
public:
CustomReferenceCounted (int* counter)
: counter_ (counter)
{
}
void Release ()
{
--(*counter_);
}
private:
int* counter_;
};
class CustomReferenceCountedDeleter
{
public:
void operator () (CustomReferenceCounted* r) const
{
r->Release ();
// So we don't leak memory in this example
delete r;
}
};
int main()
{
int counter = 1;
std::tr1::shared_ptr<CustomReferenceCounter> crc (new CustomReferenceCounted (&counter), CustomReferenceCountedDeleter ());
crc.reset ();
std::cout << counter << std::endl;
}
Usage notes
There is a slight performance hit for the shared pointer copying, so you should pass the contained object by reference (preferably) or pointer unless the called code needs a copy of the pointer (for example, when inserting into a container).
Being reference-counted, you cannot use shared pointers for cyclic data structures directly. For this, you can fall back to weak_ptr
, which does not prevent deleting the pointed-to object but allows promoting to a shared pointer if needed. For a big list of more tricks, take a look at the Boost shared_ptr documentation.
Update: Changed the link to automatically point to the latest Boost documentation.