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
class ArrayDeleter
{
public:
void operator () (T* d) const
{
delete [] d;
}
};
int main ()
{
// Usage
std::tr1::shared_ptr array (new double [256], ArrayDeleter ());
}
or, if you have Boost and included <boost/smart_ptr.hpp> and you need a temporary array
boost::scoped_array 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 (new Derived ());
// Static downcast
std::tr1::shared_ptr derived = std::tr1::static_pointer_cast (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 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] Change the link to automatically point to the latest Boost documentation.
Related posts:
You still need to include to get std::tr1::shared_ptr in GCC 4.3
You can get std::shared_ptr by including if you enable the experimental C++0x support with -std=c++0x, but you still don’t get std::tr1::shared_ptr unless you include
Gah … that should have read …
You still need to include <tr1/memory> to get std::tr1::shared_ptr in GCC 4.3
You can get std::shared_ptr by including <memory> if you enable the experimental C++0x support with -std=c++0x, but you still don’t get std::tr1::shared_ptr
My bad, yes, you’re right, thanks. With GCC 4.3 there are two ways to get shared_ptrs:
* include
<memory>, which gives you (if using –std=c++0x)std::shared_ptr* include
<tr1/memory>which givesstd::tr1::shared_ptrindependent of the standards modeOf course, you can always use
boost/tr1/memory.hppto be safe in every case.Pingback: auto_ptr,shared_ptr智能指针的使用 « 云海游鱼的Bolg