Shared pointers in C++

Having mostly been a C programmer, I’ve not kept up with C++ very much. Lately, though, I’ve been using it, and with the final adoption of the C++0x standard, I’ve started looking into the new features. Here’s one that caught my eye this morning: shared_ptr from section 20.7.2.2 of the C++0x standard.

To users of the Boost libraries, this will be old hat, but to me its quite new and exciting. shared_ptr is a class template that embodies a pointer that can be shared among different users such that when the last reference to the shared pointer is destroyed, the pointed to object is also destroyed. In effect, it is a sort of reference counted pointer. The upshot of this is that you can allocate memory with new, assigning the result to a shared_ptr, and then never have to worry about calling delete.

Here’s an example:

#include <iostream>
#include <memory>

using namespace std;

class C {
public:
    C() {
        cout << "Constructor: C" << endl;
    }
    ~C() {
        cout << "Destructor : C" << endl;
    }
};

class B {
public:
    B() {
        cout << "Constructor: B" << endl;
    }
    ~B() {
        cout << "Destructor : B" << endl;
    }
};

class A {
public:
    shared_ptr<B> pb;
    C *pc;
    A() {
        pb = shared_ptr<B>(new B);
        pc = new C;
    }
};

int main (int argc, char * argv[]) {
    A a;
}

This example compiles under GNU g++, but I’ve not tested it with any other compilers, some of which don’t have as good support for C++0x yet. You’ll need to use the –std=c++0x or –std=gnu++0x compiler options.
g++ --std=c++0x -o shared_ptr shared_ptr.cpp

If you compiler supports shared_ptr, try running this example. On my system it produces the following output:

eris@luthien:/vol0/eris/dev/study/c++/shared_ptr $ g++ --std=c++0x -o shared_ptr shared_ptr.cpp  && ./shared_ptr 
Constructor: B
Constructor: C
Destructor : B

Class A has two members, a shared_ptr to class B and a regular pointer to class C. Both are allocated with new in A‘s constructor, but neither of them is ever explicitly deleted. Indeed, A has no destructor at all. But the messages printed by the constructors and destructors of B and C let us see that the B object – held through a shared_ptr – does get it’s destructor called when the program terminates, while the C – held through a regular pointer – does not. C‘s memory has leaked through the programmer “forgetting” to define a destructor for A, but the shared_ptr to B takes care of it’s deletion for us.

In other words, a shared_ptr saves us from having to write a destructor, and helps to prevent our feet from being shot.

Very nice!