Home > Guides > Programming > C/C++

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

The weak ptr Class Template, Part I

Last updated Aug 11, 2006.

The std::tr1:shared_ptr class template is the big and famous sibling of another class template called std::tr1::weak_ptr. In this part I introduce weak_ptr, explain which programming problems it solves and how it is used.

To Have and to Own

shared_ptr differs from its nearly-extinct ancestor auto_ptr in one crucial aspect, namely resource sharing. auto_ptr implements "strict ownership", meaning it exclusively owns its bound resource. Thus, if two auto_ptrs own the same resource undefined behavior will occur. shared_ptr implements a different ownership strategy whereby multiple shared_ptr objects can safely own the same resource. This "sharing" is accomplished by reference counting. The counter is incremented every time a new shared_ptr object is bound to the same resource, and decremented whenever a shared_ptr object is destroyed. Only once the reference counter reaches zero is the shared resource released.

Statistically, I believe that the shared ownership implemented by shared_ptr is suitable for the majority of programming tasks. By now, shared_ptr is also the most widely-used standard smart pointer in C++. So why is weak_ptr necessary and how does it differ from shared_ptr?

Its Weakness is its Strength

weak_ptr offers a limited set of operations compared to shared_ptr because it’s not really a smart pointer in the classic sense. Smart pointers typically employ the RAII idiom. They lock a resource when they are constructed and release it during their destruction. Weak_ptr does neither of this. Instead, it stores a "weak reference" to an object that’s already managed by a shared_ptr. Unlike shared_ptr, weak_ptr doesn’t increment the reference counter of the shared resource. For example, if you have a shared_ptr and a weak_ptr that are both bound to the same resource, the reference count is 1, not 2:

A * pa = new A;
shared_ptr <A> sp1(pa); //reference count of pa is 1
weak_ptr<A> wp1(sp1); ////reference count of pa is 1
shared_ptr <A> sp2(sp1); //reference count of pa is 2
cout<< "use count is: "<<sp.use_count()<<endl; //2

Cyclic Dependency

weak_ptr objects are used for breaking cycles in data structures. A cycle is similar to a deadlock in multithreading: two resources hold pointers to one another so pointer a cannot be released because it’s still shared by a resource owned by pointer b. Pointer b cannot be released either because its resource is owned by pointer a. You can break such cyclic dependency by using weak_ptr instead of shared_ptr. A linked list data structure demonstrates this problem:

struct Node
{
shared_ptr<Node> next;
};
Node * phead= new Node;
Node *pn1 = new Node;
shared_ptr<Node> root(phead);
phead->next=shared_ptr <Node> (pn1);
pn1->next=root; //cycle

Let’s see how the use of weak_ptr solves this problem. First, you need to modify the Node data structure:

struct Node
{
shared_ptr<Node> next;
weak_ptr<Node> w_next;
};

Next, replace pn1-next with pn1-w_next:

Node * phead= new Node;
Node *pn1 = new Node;
shared_ptr<Node> root(phead);
phead->next=shared_ptr <Node> (pn1);
pn1->w_next=root; // no cycle

Because weak_ptr doesn’t increment or decrement the use count, it can’t own a resource that isn’t already owned by a shared_ptr object. Furthermore, a weak_ptr object might expire while it’s still alive. This can happen when the last shared_ptr object has been destroyed and released the resource. In this situation, a weak_ptr object pointing to the released resource is said to have been expired. For this reason, you can’t access the owned resource directly from a weak_ptr object. Instead, you have to construct a shared_ptr object from that weak_ptr object and access the resource through that shared_ptr object. There are two ways to do it:

constructing a shared_ptr with a weak_ptr argument. This technique is shown here:

shared_ptr<A> func(const weak_ptr<A>& wpa)
{
if (!wpa.expired())
 return shared_ptr<wpa);
return shared_ptr<A>; //empty shared_ptr
}

Always ensure that the weak_ptr hasn’t expired before you try to construct a shared_ptr from it. Constructing a shared_ptr from an expired weak_ptr throws std::tr1::bad_weak_ptr exception.

Using the weak_ptr::lock() member function. This technique doesn’t throw. lock() returns an empty shared_ptr if *this has expired. Otherwise, it returns a shared_ptr object that owns the resource to which *this is pointing (you may have noticed that lock() does what func() does).

In addition to expire(), weak_ptr includes the use_count() member function which reports how many shared_ptr objects own the resource to which *this is pointing. If wp.use_count() is higher than zero, it means that wp hasn’t expired. Technically speaking, expire() isn’t really necessary because you can obtain the same information by calling use_count(). However, some implementers reports that use_count() is in some cases less efficient than expire() so you should use the latter when possible.

In the second part of this series I will discuss additional properties of weak_ptr, including assignment, swapping, reset() and comparing weak_ptr objects.

Books

The most detailed and authoritative printed source is Pete Becker’s The C++ Standard Library Extensions: A Tutorial and Reference. Pete worked at Dinkumware Ltd., where he completed the implementation of TR1 library. He is also the project editor of C++0x, and has been a member of the C++ standards committee since its inception.

Discussions

Bugzilla
Posted Nov 18, 2008 01:53 AM by cupu
2 Replies
auto_ptr issues
Posted Sep 14, 2007 07:43 AM by singh_siddhu
1 Replies
i want c++ book through net
Posted Aug 23, 2007 11:13 PM by harivilu
3 Replies

Make a New Comment

You must log in in order to post a comment.

Related Resources

Danny KalevMinutes from the October 2009 Meeting
By Danny KalevNovember 19, 2009 No Comments

The minutes from the Santa Cruz (October 2009) meeting are available here. Even if you're not a language layer at heart, I encourage you to read them.

Danny KalevA Reader's Opinion on Attributes
By Danny KalevOctober 20, 2009 No Comments

In August I dedicated a series to the debate about C++0x attributes. I believe that it covered the subject in a balanced and detailed way, but I keep getting complaints from C++ users who don't like attributes for various reasons. Here's a recent email I received from a Polish C++ programmer. While it  doesn't represent my opinion about attributes -- I'm rather neutral about this feature and consider it a "solution waiting for a problem" -- but it suggests that attributes are still a highly controversial issue that will haunt C++ for a long time. The email is quoted here with minor edits that and as usual, with all private details removed.

Danny KalevFollowup: The Web 2.0 Guy I Ain't
By Danny KalevOctober 16, 2009 1 Comment

Almost a year ago, I posted here The Web 2.0 Guy I Ain't. People wonder whether I still resist all those Web 2.0 features and technologies at the end of 2009.

See More Blogs

Informit Network