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
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:

  1. Breaking dependencies with COM-style interfaces
  2. C++, <windows.h>, precompiled headers and pimpl
  3. Pimpl your C++ code
  4. C++ tricks, #1: Compile time checks
  5. C++ tricks, #2: Parameter passing

This entry was posted in General. Bookmark the permalink.

4 Responses to std::tr1::shared_ptr tutorial

  1. 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

  2. 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

  3. Anteru says:

    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 gives std::tr1::shared_ptr independent of the standards mode

    Of course, you can always use boost/tr1/memory.hpp to be safe in every case.

  4. Pingback: auto_ptr,shared_ptr智能指针的使用 « 云海游鱼的Bolg

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>