Browse DevX
Sign up for e-mail newsletters from DevX


Automate Resource Management with shared_ptr-2 : Page 2

Presenting the Problem
A typical smart pointer wraps a raw pointer to a dynamically allocated object and overloads the operators -> and *. The responsibility for deleting the pointer is delegated to the smart pointer's destructor, thus freeing you from manual—and bug-prone—memory management. The problem, however, is that auto_ptr, the only smart pointer class available in C++98, has peculiar copy and assignment semantics. When you assign an auto_ptr x to another auto_ptr y, not only is the target object modified (as expected) but so is the source object, which becomes null. This behavior makes auto_ptr incompatible with STL containers and algorithms. Let's see how shared_ptr solves this problem.

Author's Note: To use shared_ptr you need to download its sources from Boost. Notice that this Solution adheres to the official TR1 Draft Proposal, which differs slightly from boost::shared_ptr.

Construction and Initialization
shared_ptr's default constructor creates what is known as an empty smart pointer, i.e., an object whose pointer is null. You can assign a valid pointer to it later:

class Foo{
 int x;
 explicit Foo(int val=0) :x(val) {}
 void do_something() {/*..*/}
 int show_x() const {std::cout<< x<<std::endl; }

#include <memory> //for shared_ptr
using std::tr1::shared_ptr;
int main()
 shared_ptr<Foo> pf; //pf is an empty shared_ptr
 //bind a "live" pointer to pf
 pf=new Foo;
 pf->do_mesomething(); //using shared_ptr's overloaded ->
 (*pf).show_x();//using shared_ptr's overloaded *
}//pf's destructor called here, destroying Foo
shared_ptr defines a conversion operator to bool. This is useful for testing whether the shared_ptr is empty. To access the raw pointer directly, call get():

if (pf) { //ensure that pf isn't empty before calling get
 Foo *palias = pf.get();
The second shared_ptr constructor takes a pointer to a dynamically allocated object and an optional deleter. The following example defines a deleter and passes its address to shared_ptr's constructor:

void my_deleter(Foo *ptr)
 delete ptr;
 std::cout<< "using custom deleter" <<std::endl;
shared_ptr<Foo> pf (new Foo, my_deleter); 
A deleter can be any callable entity: a free function, a function object, etc. When a user-defined deleter d is provided, shared_ptr's destructor calls:

Instead of deleting ptr directly. A custom deleter enables you to bind shared_ptr to a pointer that was allocated in a different DLL, for example.

Certain resources such as file descriptors, synchronization objects, and device contexts require that a special API function be called to release them. Using a custom deleter, shared_ptr can manage such resources elegantly. In the following example, shared_ptr holds a mutex pointer obtained from an API function. When the shared_ptr object is destroyed, the release_mutex() function is called automatically:

//API functions for acquiring and releasing a mutex
mutex_t* get_mutex(pid_t pid);
int release_mutex(mutex_t* pmx);

shared_ptr <mutex_t> pmutex (get_mutex(mypid),               

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