- Overview
- Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
- Tips and Techniques
- A Tour of C99
- C++0X: The New Face of Standard C++
- Reference Wrapper
- The Performance Technical Report
- auto for the People
- Ironing Templates' Syntactic Wrinkles
- Visual C++ Becomes ISO Compliant
- A Garbage Collector for C++
- C99 Core Features in C++0X
- The
shared_ptrClass - The shared_ptr Class, II
- Lambda Expressions and Closures, Part I
- Lambda Expressions and Closures, Part II
- Lambda Expressions and Closures, Part III
- The Type Traits Library, Part I
- The Type Traits Library, Part II
- The Type Traits Library, Part III
- finally Revisited
- The Any Library
- The nullptr Keyword Proposal
- Delegating Constructors
- The Explicit Conversion Operators Proposal
- Conditionally-Supported Behavior
- The weak ptr Class Template, Part I
- The weak ptr Class Template, Part II
- POD Types Revisited
- The rvalue Reference Proposal, Part I
- The rvalue Reference Proposal, Part II
- Proposal for New String Algorithms
- Concepts, Part I
- Concepts, Part II
- constexpr: Generalized Constant Expressions
- The constexpr Proposal: Constructors
- Strongly-Typed enum Types
- C++09: The Road Ahead
- C++09: Proposals by Statuses
- Changing Undefined Behavior to Diagnosable Errors
- New Character Types
- The __func__ Predeclared Identifier is Coming to C++
- Static Assertions
- The extern template Proposal
- Variadic Templates, Part I
- Variadic Templates, Part II
- Variadic Templates, Part III -- Critique
- Using unique_ptr, Part I
- Using unique_ptr, Part II
- Unrestricted Unions, Part I
- Unrestricted Unions, Part II
- Unrestricted Unions, Part III
- Types With No Linkage as Template Arguments
- New Initialization Syntax
- Initializer Lists and Sequence Constructors
- New Standard Library Algorithms
- Class Member Initializers
- Inheriting Constructors
- Introducing Attributes
- The Removal of Concepts From C++0x
- The Future of C++0x, Part I
- The Future of C++0X, Part II
- The Debate About Attributes, Part I
- The Debate About Attributes, Part II
- The Debate About Attributes, Part III
- The Debate About Attributes, Part IV New
- Forward Declarations of Enum Types
- The SCARY Iterators Proposal, Part I
- The SCARY Iterators Proposal, Part II
- Heading for Deprecation: export, Exception Specification and register New
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
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.


Account Sign In
View your cart