std::tr1::shared_ptr tutorial

This post is very old. Please bear in mind that information here might be incorrect or obsolete, and links can be broken. If something seems wrong, please feel free to comment or contact me and I'll update the post.

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. C++, ownership and shared_ptr
  2. Boost::Signal inside a std::map
  3. C++, <windows.h>, precompiled headers and pimpl

This entry was posted in Programming and tagged , . Bookmark the permalink.

6 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

  5. Pingback: Spaß mit stl::shared_ptr auf ein c-array in C++ (Memory Tester) « Wissenswertes

  6. Nickolay says:

    shared_ptr is not an addition to the STL. It is an addition to the C++ Standard Library.
    Standard Library and STL are not the same.

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>