Home > Programming > Memory Management: Smart Pointers

Memory Management: Smart Pointers

One of the most important things to deal with when programming is resource management. When using a language like C++ memory is one of those precious resources that are not handled for you. Whenever you deal with the heap it’s important to keep track of everything you do to prevent memory leaks and other fun bugs that can creep up on you. So what are some ways to keep ensure your program doesn’t go eating up all your important memory?

Well perhaps every time you write something like int* i = new int; you could immediately write it up like so:
int* i = new int;
// insert code here
delete i;

Therefore ensuring you don’t forget to free up the memory. Seems a little cluttered to me, I’m very forgetful. Wouldn’t it be awesome if something could handle deleting the pointer for you? We could go on a tangent describing how to create your own class to handle this, deleting the pointer in the destructor and all, but let’s skip right to the fun — smart pointers. For this post we’re going to use the boost smart pointer library which contains scoped_ptr, scoped_array, shared_ptr, and shared_array. Let’s take a look at them.

scoped_ptr and scoped_array

It’s very easy to describe these: they hold a pointer, delete it upon destruction, give you access to it, don’t allow copies. Simple right? I’m going to assume you’re familiar with templates and gloss over that part since these are all templated classes. Let’s take a look at some sample code:

int main() {
boost::scoped_ptr<int> bspInt(new int(42));
boost::scoped_array<int> bspIntArray(new int[5]({1,2,3,4,5}));
boost::scoped_ptr<int> bspInt2;
// bspInt2 = bspInt; // will not work, cannot use operator=
cout << *bspInt << endl; // prints 42
cout << bspIntArray[0] << endl; // prints 1
bspInt2.reset(new int(7)); // works fine
cout << *bspInt2 << endl; // prints 7
cout << bspInt.get() << endl; // prints the address of the pointer
return 0; // destruction causes all the memory to be freed appropriately
// delete is called on bspInt and bspInt2's pointers
// delete [] is called on bspIntArray's pointer.
}

Of course just because I used an int doesn’t mean you have to? It’s a template, it will work with any struct or class you can think of.

shared_ptr and shared_array

Just like the above, only this time you can copy and share the pointers. The point here is shared ownership. Now, if you don’t need shared ownership use the scoped_ptr or scoped_array. If you need ownership transfer, then use the std::auto_ptr which I’m not covering here. So, let’s take a look at sharing — because it’s fun. =)

int main() {
boost::shared_ptr<int> bspInt(new int(42));
boost::shared_array<int> bspIntArray(new int[5]({1,2,3,4,5}));
{ // artificial scope to proof a point
boost::shared_ptr<int> bspInt2;
bspInt2 = bspInt; // works fine, ref count is 2
cout << *bspInt2 << endl; // prints 42
} // close scope, bspInt2 is freed. ref count is 1
cout << *bspInt << endl; // prints 42
cout << bspIntArray[0] << endl; // prints 1
bspInt.reset(new int(7)); // works fine
cout << *bspInt << endl; // prints 7
cout << bspInt.get() << endl; // prints the address of the pointer
return 0; // destruction causes all the memory to be freed appropriately
// delete is called on bspInt's pointer
// delete [] is called on bspIntArray's pointer.
}

So there ya have it. Effective easy memory management. Shared pointers are especially useful for returning pointers from functions, remember scoped_ptr’s can’t be copied, so you would need a shared_ptr to return it. So let’s recap: smart pointers are used like any other pointer with * to dereference and -> to call methods and access members. They handle memory management for you to make life easier. So the next time you’re considering using a pointer, think about using a smart pointer instead. Takes a lot of the headache out of keeping track of your memory.

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Your email address will not be published.