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 {
public:
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.