C++ Blog

C++ Weak Pointers

Posted in boost by Umesh Sirsiwal on January 5, 2009

C++ TR1 has added concept of weak pointers. Most of the C++ developers understand use of shared pointers but they don’t understand use of weak pointers very well.

Weak Pointer Definition

According to boost:

The weak_ptr class template stores a “weak reference” to an object that’s already managed by a shared_ptr. To access the object, a weak_ptr can be converted to a shared_ptr using the shared_ptr constructor or the member function lock. When the last shared_ptr to the object goes away and the object is deleted, the attempt to obtain a shared_ptr from the weak_ptr instances that refer to the deleted object will fail: the constructor will throw an exception of type boost::bad_weak_ptr, and weak_ptr::lock will return an empty shared_ptr.

There is no way to directly access underlying resources managed by the weak_ptr. In order to access the underlying pointer the weak pointer must be converted to a shared_ptr using lock or shared_ptr constructor.


shared_ptr<int> p(new int(5));

weak_ptr<int> q(p);

// some time later

if(shared_ptr<int> r = q.lock()) {

// use *r

}

Weak Pointer Usage

This all looks interesting but where will one use it. DDJ covered this subject in one of its articles. Consider an application where thread reads messages from a queue operators on it and then sends response back to the queue. This is tricky if the processing of the message can take a significant time. In order to correctly send back the response the message must hold a reference to the queue. The problem is that the queue may close before the response is ready to be sent. One possible solution is to store shared pointer to queue in the message structure:

shared_ptr<QueueType> q;

struct {

shared_ptr<QueueType> q;

} MessageType;

MessageType m;

m = q->Get();

m.q = q; //m.q holds a shared reference to the queue

...

...

m.q.Send(data);

If the queue is closed after putting a reference to the queue in the message, the queue cannot be destroyed since it is shared pointer. In some of the applications number of messages may be 1000s and can significantly delay queue destruction. A far better alternative is to put a weak_pointer to the queue in the message structure and check the queue state before calling the send. The modified code looks like the following:

shared_ptr<QueueType> q;

struct {

weak_ptr<QueueType> q;

} MessageType;

MessageType m;

m = q->Get();

m.q = q; //m.q holds a  weak reference to the queue. If the queue is closed, the underlying object can be destroyed and resources reclaimed.

...

...

if (shared_ptr<QueueType> realq = m.q.lock() ) {

realq.Send(data);

}

This code segment allows early destruction of queue to reclaim resources.