Browse DevX
Sign up for e-mail newsletters from DevX


Automate Resource Management with shared_ptr-3 : Page 3

Counting on Reference Counting
Each shared_ptr destructor call decrements the bound pointer's reference count. When the reference count reaches 0, the pointer is deleted. This property enables you to combine shared_ptr with STL containers and algorithms. The following example of creating a heterogeneous container is based on my September 2000 10-Minute Solution. This version however uses shared_ptr instead of bare pointers.

First, review the class hierarchy:

class mutimedia_file {
 explicit mutimedia_file(const string& filename);
 virtual ~mutimedia_file();
 int virtual play();
class wav_file : public mutimedia_file;
class mp3_file : public mutimedia_file;
class ogg_file : public mutimedia_file;
Here's how you populate the vector with heterogeneous shared_ptrs:

typedef std::tr1::shared_ptr <multimedia_file*> Pmm;
typedef std::vector <Pmm>  Vpmm;

void fill_and_play(Vpmm & v) 
 Pmm temp(new mp3_file("crazy4u"));//#1 create shared_ptr
 v.push_back(temp);//#2 store a copy of temp in v 
   //reuse temp 
 temp.reset(new wav_file("email_alert")); #3
 v.push_back(temp); // insert shared_ptr<wav_file*> to v
 v[0]->play(); // mp3_file::play()
 v[1]->play(); // wav_file::play()
Notice how fill() recycles the same shared_ptr object by calling the reset() member function. temp.reset(p2) causes temp to replace its existing pointer p with p2 and decrement p's reference count. Because a copy of the original shared_ptr has already been stored in the vector (line #2), p's reference count is higher than 0, and therefore the reset() call doesn't delete the original pointer allocated in line #1. When fill() exits, temp is destroyed but the shared_ptrs stored in v keep the reference count of all pointers above 0. These pointers are deleted only when v itself is destroyed.

As far as heterogeneity is concerned, the code works correctly because assigning shared_ptr<T> or T* to shared_ptr <U> is perfectly legal as long as there is an implicit conversion from T* to U*. Furthermore, you can use a shared_ptr<void> to store any pointer type in the container since shared_ptr's constructor is templated on the argument's type:

shared_ptr <void> pf(new Foo);//fine
When pf is destroyed, it invokes Foo's destructor, as expected.

Thanks for your registration, follow us on our social networks to keep up-to-date