I am starting this blog as a way to learn some concepts that I haven’t previously taken the time to learn.  While it will probably end up being mostly coding material, I may occasionally throw some more stuff in, assuming I continue this past one blog post.

Smart Pointers: Introduction

The first topic I am going to tackle is smart pointers.  I am going to try to understand the basics as well as some of the more intricate details.  I’m going to start with some of the basics of memory allocation and scoping, then go in to the uses of smart pointers.

First, let’s define a class:

using namespace std;
class Movie {
 public:
 Movie(string title):title_(title) {};
 Movie():title_(0) {};
~Movie() { cout << "Destructor Called!\n"; }
 inline string title() {return title_;};
 private:
 string title_;
};

The Basic Method

Movie movie("Gattaca");
cout << movie.title() << endl;

This creates an instance of the class which will call the destructor when the variable goes out of scope. We could also create a pointer to the movie and dynamically create the object with the new command, but we have to remember to use delete to call the destructor, or it will cause a memory leak:

 Movie *movie_p = new Movie("Gattaca");
 cout << movie_p->title() << endl;
 delete movie_p;

scoped_ptr and unique_ptr

The boost smart pointer solution to this is to use the scoped_ptr. The destructor is called when movie_p goes out of scope, so we don’t have to worry about the possibility of forgetting to use delete:

#include <boost/scoped_ptr.hpp>
...
boost::scoped_ptr movie_p(new Movie("Gattaca"));
cout << movie_p->title() << endl;

C++11 implements the unique_ptr, which acts like the scoped_ptr. I also needed to include the compiler option -std=c++0x to get the new C++ functionality:

#include
...
unique_ptr movie_p(new Movie("Gattaca"));
cout << movie_p->title() << endl;

Note that we cannot make a copy of this pointer, as in:

//this code gives a compiler error
unique_ptr movie_p(new Movie("Gattaca"));
{
	unique_ptr movie_p2 = movie_p; //Not allowed!
}
cout << movie_p->title() << endl;

If this was allowed, then the instance of Movie would get deleted when movie_p2 went out of scope, and movie_p would no longer point to anything when we tried to use it. C++11 would allow us to transfer the pointer however:

//this code will segfault
unique_ptr movie_p(new Movie("Gattaca"));
{
	unique_ptr movie_p2 = std::move(movie_p);
}

The instance of Movie is now deleted when movie_p2 goes out of scope. movie_p no longer points to anything because of the move. Note that since we can’t create a copy of the pointer, we would have to pass it by reference to a function if we wanted to use it.

scoped_array

scoped_ptr can not be used to create dynamic arrays. Boost has a separate method, scoped_array, that allows the creation of smart dynamic arrays.

If we want to create a array of dynamic size the traditional way, we would use:

Movie *movie_ar = new Movie[3];
cout << movie_ar[1].title() << endl;
delete [] movie_ar;

Where as the boost smart pointer method would be:

#include <boost/scoped_array.hpp>
...
boost::scoped_array movie_ar(new Movie[3]);
cout << movie_ar[1].title() << endl;

The C++11 method still allows us to use unique_ptr, but we would define it as:

unique_ptr movie_ar(new Movie[3]);
cout << movie_ar[1].title() << endl;

Of course, I prefer to use std::vector for any dynamic array needs. Note that one of the major downsides of the above methods is that we had to use the default constructor, so we could not initialize the array to anything we wanted. std::vector provides a lot more flexibility when working with arrays, and still handles the memory management issues.

shared_ptr and weak_ptr

scoped_ptr and unique_ptr are useful, but they have some limitations since we can’t create copies of them. scoped_ptr and unique_ptr own a resource and don’t allow any other variables to claim ownership. shared_ptr owns a resources, but allows other shared_ptrs to claim ownership. The key is that it keeps track of how many shared_ptrs claim ownership, and deletes the resource when the last shared_ptr releases its claim. (Note that C++11 also uses shared_ptr and weak_ptr, and the implementation is the same as far as I know)

boost::shared_ptr movie_p(new Movie("Gattaca"));
{
	boost::shared_ptr movie_p2 = movie_p;
	cout << movie_p2->title() << ", " << movie_p.use_count() << endl;
}
cout << movie_p->title() << ", " << movie_p.use_count() << endl;
//outputs:
//Gattaca, 2
//Gattaca, 1
//Destructor Called

movie_p is copied by movie_p2, but movie_p knows that it has been copied as can be seen by the output of the use_count. The destructor is not called when movie_p2 goes out of scope since movie_p is still in scope. However, be careful to make sure you copy the shared_ptr, and not the raw pointer, as in this example of bad code:

Movie *raw_p = new Movie("Gattaca");
boost::shared_ptr<Movie> movie_p(raw_p);
{
	boost::shared_ptr<Movie> movie_p2(raw_p);
	cout << movie_p2->title() << ", " << movie_p.use_count() << endl;
}
cout << movie_p->title() << ", " << movie_p.use_count() << endl;
//output:
//Gattaca, 1
//Destructor Called!
//, 1
//Destructor Called! --Trying to delete something that is not there!  Causes crash.

In this example, we create a raw pointer, then pass it to both shared_ptrs. This results in each shared_ptr thinking it is the only one that owns the resource. If you need to create a shared_ptr from this, use shared_from_this: http://alsharabi.blogspot.com/2009/03/why-use-sharedfromthis.html

We can also create weak_ptr from a shared_ptr. A weak_ptr will point to the object, but will not count as an extra copy. This means that if all of the shared_ptrs go out of scope, or are reset, then weak_ptr will not point to anything. So, since there is no guarantee that the weak_ptr points to anything, you cannot use it to directly access the object. You must first turn it in to a shared_ptr to use it:

boost::shared_ptr movie_p(new Movie("Gattaca"));
boost::weak_ptr movie_pw(movie_p);
cout << movie_p->title() << ", " << movie_p.use_count() << endl;
if(boost::shared_ptr movie_ptemp=movie_pw.lock()) cout << movie_ptemp->title() << ", " << movie_p.use_count() << endl;
else cout << "movie_pw did not point to anything!\n";
movie_p.reset(new Movie("Braveheart"));
cout << movie_p->title() << ", " << movie_p.use_count() << endl;
if(boost::shared_ptr movie_ptemp=movie_pw.lock()) cout << movie_ptemp->title() << ", " << movie_p.use_count() << endl;
else cout << "movie_pw did not point to anything!\n";
//outputs:
//Gattaca, 1
//Gattaca, 2
//Destructor Called!
//Braveheart, 1
//movie_pw did not point to anything!
//Destructor Called!

So, a couple things to note here. The use_count is still 1 after we create the weak_ptr, but it becomes 2 when we turn the weak_ptr into a shared_ptr to use it. We then reset movie_p and made it point to something else. The movie that the weak_ptr was originally pointing to has now been destroyed, so when we try to use it, we fail. So, weak_ptr allowed us to keep track of the resource, without preventing the resource from being destroyed.

When to use a weak_ptr

Since we have to turn a weak_ptr into a shared_ptr to use it, it raises the question of when we would ever actually want to use a weak_ptr. Let’s look at a couple examples of where they become useful. The standard use mentioned is breaking cyclic shared_ptr references. This problem occurs with something like:

//add this line to Movie class:
boost::shared_ptr other_movie_p;
...
boost::shared_ptr movie_p(new Movie("Gattaca"));
movie_p->other_movie_p = movie_p;
cout << movie_p->title() << ", " << movie_p.use_count() << endl;
//outputs:
//Gattaca, 2

In this example, we added a shared_ptr to the Movie class, then set it equal to a shared_ptr that points to itself. Note that the destructor is not called in this case, so we end up with a memory leak. Essentially the problem is that when movie_p goes out of scope, it thinks another shared_ptr (other_movie_p) is holding on to its resource, so it does not delete the Movie. But other_movie_p will never drop the resource since it never gets deleted. We can resolve this by making other_movie_p a weak_ptr:

boost::weak_ptr other_movie_p;
...
boost::shared_ptr movie_p(new Movie("Gattaca"));
movie_p->other_movie_p = movie_p;
cout << movie_p->title() << ", " << movie_p.use_count() << endl;
//outputs:
//Gattaca, 1
//Destructor Called!

So now, other_movie_p is not stopping the Movie from being destroyed.

We could also imagine a scenario where we would like to keep a pointer to the movie, but we don’t want that pointer to share ownership of the movie. Consider a case where we index our movie collection:

boost::shared_ptr movie_p1(new Movie("Gattaca"));
boost::shared_ptr movie_p2(new Movie("Braveheart"));

vector<boost::shared_ptr > movieindex;
movieindex.push_back(movie_p1);
movieindex.push_back(movie_p2);

for(size_t i=0; i < movieindex.size(); i++) cout << "Movie " << i << " is " << movieindex[i]->title() << endl;

movie_p1.reset(); //I lost Gattaca. Very sad.

for(size_t i=0; i < movieindex.size(); i++) cout << "Movie " << i << " is " << movieindex[i]->title() << endl;
//output:
//Movie 0 is Gattaca
//Movie 1 is Braveheart
//Movie 0 is Gattaca
//Movie 1 is Braveheart
//Destructor Called!
//Destructor Called!

On line 10, I call reset on the movie_p1. I could consider this to be losing the movie. But, since a copy of the shared pointer is still stored in the index, the resource has not been deleted. If this were a reflection of real life, indexing your movie collection would ensure that you could never lose any of the movies! Great, but unrealistic.

Let’s consider this example again, but using weak_ptr for the index:

boost::shared_ptr movie_p1(new Movie("Gattaca"));
boost::shared_ptr movie_p2(new Movie("Braveheart"));

vector<boost::weak_ptr > movieindex;
movieindex.push_back(movie_p1);
movieindex.push_back(movie_p2);

for(size_t i=0; i < movieindex.size(); i++) {
	if(boost::shared_ptr movie_ptemp=movieindex[i].lock()) cout << "Movie " << i << " is " << movie_ptemp->title() << endl;
	else cout << "Movie " << i << " has been lost!\n";
}
movie_p1.reset(); //I lost Gattaca. Very sad.

for(size_t i=0; i < movieindex.size(); i++) {
	if(boost::shared_ptr movie_ptemp=movieindex[i].lock()) cout << "Movie " << i << " is " << movie_ptemp->title() << endl;
	else cout << "Movie " << i << " has been lost!\n";
}
//output:
//Movie 0 is Gattaca
//Movie 1 is Braveheart
//Destructor Called!
//Movie 0 has been lost!
//Movie 1 is Braveheart
//Destructor Called!

In this example, when we reset movie_p1, we deleted the resource, so that when we try to look it up later, we find it is not there. Essentially, the separate lifetimes of the object and the pointer must be considered when using weak or shared pointers.

intrusive_ptr

An intrusive_ptr is designed to operate like a shared_ptr, except that it doesn’t have the built in machinery to do so automatically. It will keep track of its copies and delete itself when the number of copies goes to zero, just like a shared_ptr. However, you must specifically define some of the functions for doing this yourself. The payoff for doing so is a lower memory footprint for each intrusive_ptr, and therefore better performance. The boost documentation states: “As a general rule, if it isn’t obvious whether intrusive_ptr better fits your needs than shared_ptr, try a shared_ptr-based design first.”

So let us look at an intrusive_ptr implementation. I am going to walk through a minimal implementation, but a better implementation can be found at http://alsharabi.blogspot.com/2009/06/boostintrusiveptr-is-one-of-six-smart.html. If we try to create an intrusive_ptr with our existing Movie class, we will get a compiler error complaining about the lack of two functions, intrusive_ptr_add_ref and intrusive_ptr_release. The first is for adding to the reference count when we make a copy, and the second is for when we delete one of the copies. So, we can add the following functions to our Movie class:

#include <boost/intrusive_ptr.hpp>
...
using namespace std;
class Movie {
public:
	Movie(string title):use_count_(0),title_(title) {};
	Movie():use_count_(0),title_(0) {};
	~Movie() { cout << "Destructor Called!\n"; }
	inline string title() {return title_;};
	friend void intrusive_ptr_add_ref(Movie * p) {
		p->use_count_++;
	};
	friend void intrusive_ptr_release(Movie * p) {
		if(--p->use_count_==0) {
			delete p;
		}
	};
	inline int use_count() {return use_count_;};
private:
	int use_count_;
	string title_;
};
..
Movie *raw_ptr = new Movie("Gattaca");
boost::intrusive_ptr<Movie> movie_p(raw_ptr);
{
	boost::intrusive_ptr<Movie> movie_p2(movie_p);
	cout << movie_p2->title() << ", " << movie_p->use_count() << endl;
	boost::intrusive_ptr<Movie> movie_p3(raw_ptr);
	cout << movie_p3->title() << ", " << movie_p->use_count() << endl;
}
cout << movie_p->title() << ", " << movie_p->use_count() << endl;
//output:
//Gattaca, 2
//Gattaca, 3
//Gattaca, 1
//Destructor Called!

So, in this code, we have declared a reference counter, use_count_, as part of the Movie class, and the two required functions, intrusive_ptr_add_ref and intrusive_ptr_release. Note that we could not declare the functions as member functions since the intrusive_ptr calls intrusive_ptr_add_ref, but not p->intrusive_ptr_add_ref. Making it a friend function still puts it in a global scope, but allows it access to the private members of the class. We could have made the reference counter public and put the functions outside the class, but that is a bit messier.

Note that in this example, we make copies both by passing the intrusive_ptr and by passing the raw pointer. Passing the raw pointer does not cause a problem like it did in the shared_ptr case since the object itself keeps track of the reference count.

I don’t believe that there would be a weak_ptr equivalent for intrusive_ptr since the object keeps track of its references, and if it gets deleted, there is no simple way to check that the reference count has gone to zero. However, since you have control of the reference counting and deleting, you could presumably get more creative to avoid cyclic references.

Performance Comparison: shared_ptr vs intrusive_ptr

So, is the extra effort for intrusive_ptr worth it? I’ll test the performance using the following code:

for(size_t i=0; i < 10000000; i++) {
	boost::shared_ptr<Movie> movie_p(new Movie("Gattaca"));
}
//takes 2.027s with intrusive_ptr machinery in place
//takes 1.909s without intrusive_ptr machinery in place
for(size_t i=0; i < 10000000; i++) {
	boost::intrusive_ptr<Movie> movie_p(new Movie("Gattaca"));
}
//takes 1.222s

This code simply creates and destroys a bunch of objects. We can see that using the intrusive_ptr has a clear performance advantage. At first I ran the code with identical classes, but then tried the shared pointer case again after taking out the stuff we added to the Movie class to enable the intrusive_ptr. Removing it had a small effect, and the intrusive_ptr is still the clear winner.

for(size_t i=0; i < 10000; i++) {
	vector<boost::shared_ptr<Movie> > movie_pointers;
	movie_pointers.reserve(10000); //removed in first test case
	boost::shared_ptr<Movie> movie_p(new Movie("Gattaca"));
	for(size_t j=0; j < 10000; j++) {
		movie_pointers.push_back(movie_p);
	}
}
//without reserve: 14.502s
//with reserve: 5.388s
for(size_t i=0; i < 10000; i++) {
	vector<boost::intrusive_ptr<Movie> > movie_pointers;
	movie_pointers.reserve(10000); //removed in first test case
	boost::intrusive_ptr<Movie> movie_p(new Movie("Gattaca"));
	for(size_t j=0; j < 10000; j++) {
		movie_pointers.push_back(movie_p);
	}
}
//without reserve: 9.194s	
//with reserve: 3.530

These code segments basically just create and destroy a lot of pointers, and make lots of copies. We can see that once again, the intrusive_ptr is a clear winner. It also reminds us of the importance of using reserve for vectors.

Alright, that’s all for now on smart pointers. If I find anything else interesting about them, I’ll try to add it to this post.