• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Beware of Pointers
 

Beware of Pointers

on

  • 3,324 views

I talk on a variety of Smart Pointers in this lecture as Memory Management idioms in C++.

I talk on a variety of Smart Pointers in this lecture as Memory Management idioms in C++.

Statistics

Views

Total Views
3,324
Views on SlideShare
3,284
Embed Views
40

Actions

Likes
3
Downloads
122
Comments
0

5 Embeds 40

http://www.linkedin.com 21
http://www.mindtalk.com 9
http://m.mindtalk.com 8
http://apps.mindtalk.com 1
https://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • An object has ValueSemantics when it can be treated as a single value. In C++ this means implementing a copy constructor and an assignment operator in such a way that when a new or existing instance is set equal to some other instance the new instance will be equivalent to the old one without acting as an alias to it. In computing , a first-class object (also -value , -entity , -citizen ), in the context of a particular programming language , is an entity which can be used in programs without restriction (when compared to other kinds of objects in the same language). Depending on the language, this can imply: being expressible as an anonymous literal value being storable in variables being storable in data structures having an intrinsic identity (independent of any given name) being comparable for equality with other entities being passable as a parameter to a procedure/function being returnable as the result of a procedure/function being constructable at runtime For example, in C , it is not possible to create new functions at runtime (however, see discussion ), whereas other kinds of object can be created at runtime. So functions in C are not first-class objects; sometimes they are called " second-class objects ". Similarly, strings are not first class objects in Fortran as it is not possible to assign them to variables, whereas numbers can be so assigned. Retrieved from " http://en.wikipedia.org/wiki/First-class_object "
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: cv-qualified type : http://www.embedded.com/showArticle.jhtml?articleID=9900322 A cv-qualified type has the form " cv T " where, cv is a sequence of cv-qualifiers ( const and volatile ) and T is a type (without cv-qualifiers). The sequence cv can be empty, just const by itself, just volatile by itself, or const volatile (in either order). For any two sequences of cv-qualifiers cv1 and cv2 , we say that cv1 has the same or greater cv-qualification than cv2 , and write cv1 >= cv2 , if every cv-qualifier in cv2 also appears in cv1 . If cv1 >= cv2 is false, then we say that cv1 has less cv-qualification than cv2 . “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html “ We have since produced a proof of concept implementation that follows the first model and statisfies the requirement without significant size or performance implications. As a result, this version of the proposal requires use_count() == 0 to hold for all empty pointers, and the code sample will reliably print "std::bad_weak_ptr".” – What does it mean?
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html
  • Source: “ Incomplete Types” (MSDN) http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/decla_39.asp “ Incomplete Types” (IBM) http://publib.boulder.ibm.com/infocenter/macxhelp/index.jsp?topic=/com.ibm.vacpp6m.doc/language/ref/clrc03incotyp.htm
  • Source: “ A Proposal to Add General Purpose Smart Pointers to the Library Technical Report ”, 27-Mar-03. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html

Beware of Pointers Beware of Pointers Presentation Transcript

  • October 28, November 4, December 2, 2005 Beware of Pointers! Dr. Partha Pratim Das Interra Systems (India) Pvt. Ltd. Resource Management Series
  • Resource Management
    • Beware of Pointers – Be Aware of Smart Pointers
      • Typifying pointers
      • auto_ptr
    • Issues in Resource Management
      • Object Lifetime Management
        • Singleton Objects
      • Non-Memory Resource Management
        • File Pointer, GUI, Socket, Lock, …
        • Proxy Classes
    • String Management
    • Glimpses from Boost Library / C++0x TR1
  • Motivation
    • Imbibe a culture to write “good” C++ code
      • Correct: Achieves the functionality
      • Bug free: Free of programming errors
      • Maintainable: Easy to develop & support
      • High performance: Fast, Low on memory.
    • “ C++ is an abomination to society, and is doubtlessly responsible for hundreds of millions of lost hours of productivity. ”
      • – Space Monkey as posted on kuro5him.org
  • Agenda
    • Raw Pointers – A recap
      • Operations
      • Consequences of not being an FCO
      • Pointer Hazards
    • A Pointer-free World
      • Pointers vis-à-vis Reference
      • Quick Tour of Pointer-Free Languages
  • Agenda
    • Smart Pointers in C++
      • Policies
        • Storage
        • Ownership
        • Conversion
          • Implicit Conversions
          • Null Tests
      • Checking
      • Other Design Issues
      • Performance Issues
      • Smart Pointers in Practice
    • “ Understanding pointers in C is not a skill, it's an aptitude…”
      • – Joel Spolsky in “Joel on Software - The Guerrilla Guide to Interviewing”
  • Agenda
    • std::auto_ptr
      • The Philosophy
      • Standard Interface & Sample Implementation
      • Using Idioms
      • History
      • Portability
      • Pitfalls
    • References & Credits
  • Raw Pointers A Raw Deal?
  • What is a Raw Pointer?
    • A pointer is an object that gives the address of another object (Data or Function).
    • The value of a pointer is a memory location.
    • Pointers are motivated by indirect addresses in machine languages.
    • Pointers can be typed.
    • Pointers can be typeless.
    • Alternate names: Bald, Built-in, Dull, Dumb, Native, Primitive.
    • “ Pointers: the GOTO of data structures ”
      • – P.J. Moylan in “The case against C”
    Pointered Languages : Pascal, Ada, C, C++
  • What is a Raw Pointer?
    • Raw Pointer Operations
      • Dynamic Allocation (result of) or operator&
      • Deallocation (called on)
      • De-referencing operator*
      • Indirection operator->
      • Assignment operator=
      • Null Test operator! ( operator== 0 )
      • Comparison operator== , operator!= , …
      • Cast operator(int) , operator(T*)
      • Address Of operator&
      • Address Arithmetic operator+ , operator- , operator++ , operator-- , operator+= , operator-=
      • Indexing (array) operator[]
  • What is a Raw Pointer?
    • Typical use of Pointers
      • Essential – Link (‘next’) in a data structure
      • Inessential – Apparent programming ease
        • Passing Objects in functions: void MyFunc(MyClass *);
        • ‘ Smart’ expressions: while (p) cout << *p++;
    • Is not a “First Class Object”
      • An integer value is a FCO
    • Does not have a “Value Semantics”
      • Cannot COPY or ASSIGN at will
    • Weak Semantics for “Ownership” of pointee
  • Ownership Issue of Pointers
    • Ownership Issue – ASSIGN problem
    • Memory Leaks!
    // Create ownership MyClass *p = new MyClass; // Lose ownership p = 0;
  • Ownership Issue of Pointers
    • Ownership Issue – COPY problem
    • Double Deletion Error!
    // Create ownership MyClass *p = new MyClass; // Copy ownership – no Copy Constructor! MyClass *q = p; // Delete Object & Remove ownership delete q; // Delete Object – where is the ownership? delete p;
  • Ownership Issue of Pointers
    • Ownership Issue – SCOPE problem
    • Memory Leaks due to stack unrolling!
    void MyAction() { // Create ownership MyClass *p = new MyClass; // What if an exception is thrown here? p->Function(); // Delete Object & Remove ownership delete p; }
  • Ownership Issue of Pointers
    • try-catch solves this case
    void MyAction() { MyClass *p = 0; try { MyClass *p = new MyClass; p->Function(); } catch (…) { delete p; // Repeated code throw; } delete p; }
  • Ownership Issue of Pointers
    • Exceptional path starts dominating regular path
    void MyDoubleAction() { MyClass *p = 0, *q = 0; try { MyClass *p = new MyClass; p->Function(); MyClass *q = new MyClass; q->Function(); } catch (…) { delete p; // Repeated code delete q; // Repeated code throw; } delete p; delete q; }
  • Pointer Hazards
    • Pointer issues dominate all Memory Errors in C++
      • Null Pointer Dereference
      • Dangling pointers
      • Double Deletion Error
      • Allocation failures
      • Un-initialized Memory Read
      • Memory Leaks
      • Memory Access Errors
      • Memory Overrun
      • Exception al Hazards
    • “ If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization. ”
      • – Weinberg's Second Law
  • Pointer Hazards: PREfix Simulation Results
  • A Pointer-free World Reality or Utopia?
  • How to deal with an Object?
    • The object itself –
      • by value
        • Performance Issue
        • Redundancy Issue
    • As the memory address of the object –
      • by pointer
        • Lifetime Management Issue
        • Code Prone to Memory Errors
    • With an alias to the object –
      • by reference
        • Good when null-ness is not needed
        • Const-ness is often useful
  • Pointers vis-à-vis Reference
    • Use ‘Reference’ to Objects when
      • Null reference is not needed
      • Reference once created does not need to change
    • Avoids
      • The security problems implicit with pointers
      • The (pain of) low level memory management (i.e. delete)
    • W/o pointer – Use
      • Garbage Collection
    • “ Avoid working with pointers.
    • Consider using references instead. ”
      • “ Avoiding Common Memory Problems in C++” –
      • MSDN Article
  • Pointers-free Languages
    • What is a pointer-free language?
      • There is no high-level construct to directly access the address of an Object
      • Internally, the language may use indirect addressing
      • Some pointer-free languages expose pointers through ‘illegal’ or ‘unsafe’ means
  • Pointers-free Languages
    • Fortran
      • Use arrays to link
    • VB / VB.Net
      • Use Win32 API / Un-documented Functions to create pointers (link data structures)
  • Pointers-free Languages
    • Java
      • Internally every Java object is accessed through a pointer
      • Explicit pointer in native method calls
    “ Most studies agree that pointers are one of the primary features that enable programmers to put bugs into their code. Given that structures are gone, and arrays and strings are objects, the need for pointers to these constructs goes away . ” – The Java Language Environment: A White Paper , Sun 1995. ( http://java.sun.com )
  • Pointers-free Languages
    • C#
      • Pointers omitted in core language
      • Can still be used in “Unsafe Code”
        • Modifier “ unsafe ”
        • Interfacing with the underlying operating system
        • Accessing a memory-mapped device
        • Implementing a time-critical algorithm
  • Pointers-free Languages
    • D Programming Language
      • Dynamic arrays instead of pointers
      • Reference variables / objects instead of pointers
      • GC instead of explicit memory management
      • Vastly reduced need for pointers
    “ Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary. ” – Revised Report on Scheme, 1991
  • Pointers-free Languages
    • SmallTalk
    • Eiffel ( www.eiffel.com )
      • Has no pointers only – object references.
      • Exact referencing mechanism does not matter.
      • In the expression x.f, the reference x might be:
        • A pointer to an object in the same address space, or
        • An Internet address of an object.
      • References enable the location and access method of an object to be transparent.
    • BETA
    “ A language that doesn't affect the way you think about programming, is not worth knowing. ” – Alan Perlis
  • Smart Pointers in C++ The Smartness …
  • What is Smart Pointer?
    • A Smart pointer is a C++ object
    • Stores pointers to dynamically allocated (heap / free store) objects
    • Improves raw pointers by implementing
      • Construction & Destruction
      • Copying & Assignment
      • Dereferencing:
        • operator–>
        • unary operator*
    • Grossly mimics raw pointer syntax & semantics
  • What is Smart Pointer?
    • Performs extremely useful support tasks
      • RAII – Resource Acquisition is Initialization Idiom
      • Selectively disallows “unwanted” operations
        • Address Arithmetic
      • Lifetime Management
        • Automatically deletes dynamically created objects at appropriate time
        • On face of exceptions – ensures proper destruction of dynamically created objects
        • Keeps track of dynamically allocated objects shared by multiple owners
      • Concurrency Control
  • A Simple Smart Pointer
    • template <class T> class SmartPtr {
    • public:
    • // Constructible. No implicit conversion from Raw ptr
    • explicit SmartPtr(T* pointee): pointee_(pointee);
    • // Copy Constructible
    • SmartPtr(const SmartPtr& other);
    • // Assignable
    • SmartPtr& operator=(const SmartPtr& other);
    • // Destroys the pointee
    • ~SmartPtr();
    • // Dereferencing
    • T& operator*() const { ... return *pointee_; }
    • // Indirection
    • T* operator->() const { ... return pointee_; }
    • private:
    • T* pointee_; // Holding the pointee
    • };
  • A Smart Pointer mimics a Raw Pointer
    • class MyClass {
    • public:
    • void Function();
    • };
    • // Create a smart pointer as an object
    • SmartPtr<MyClass> sp(new MyClass);
    • // As if indirecting the raw pointer
    • sp->Function(); // (sp.operator->())->Function()
    • // As if dereferencing the raw pointer
    • (*sp).Function();
  • Smart Pointer Member Functions
    • Potential Name Conflict with pointee type
    • Method at namespace
    SmartPtr<Printer> spRes = ...; spRes->Acquire(); // acquire the printer ... print a document ... spRes->Release(); // release the printer spRes.Release(); // release the pointer to the printer // GetImpl returns the pointer object stored by SmartPtr template <class T> T* GetImpl(SmartPtr<T>& sp); // GetImplRef returns a reference to the pointer stored by SmartPtr template <class T> T*& GetImplRef(SmartPtr<T>& sp); // Reset resets the underlying pointer to another value, // Releases the previous one template <class T> void Reset(SmartPtr<T>& sp, T* source); // Release releases ownership of the smart pointer template <class T> void Release(SmartPtr<T>& sp, T*& destination);
  • A Smart Pointer Use-Case
    • A Distributed System
    • Objects can be
      • Local: Access is simple & fast
      • Remote: Access is involved & costly
    • How can an application code handle local & remote objects uniformly, robustly and elegantly?
  • A Smart Pointer Use-Case
    • template<class T> // Template for Smart
    • class DBPtr { // Pointers to objects
    • public: // in a distributed DB
    • DBPtr(T *realPtr = 0); // Create a Smart ptr to a
    • // DB object given a local
    • // raw pointer to it
    • DBPtr(DataBaseID id); // Create a smart ptr to a
    • // DB object given its
    • // unique DB identifier
    • ... // other smart ptr functions
    • };
  • A Smart Pointer Use-Case
    • class Tuple { // class for database tuples
    • public: ...
    • void displayEditDialog(); // present a graphical
    • // dialog box allowing a
    • // user to edit the tuple
    • bool isValid() const; // return whether *this
    • }; // passes validity check
    • template<class T> // template class for making
    • class LogEntry { // log entries whenever a T
    • public: // object is modified
    • // Begins log entry
    • LogEntry(const T& objectToBeModified);
    • // Ends log entry
    • ~LogEntry();
    • };
  • A Smart Pointer Use-Case
    • void editTuple(DBPtr<Tuple>& pt) {
    • LogEntry<Tuple> entry(*pt); // make log entry // for this edit
    • // Repeat display edit dialog for valid values
    • do {
    • pt->displayEditDialog();
    • } while (pt->isValid() == false);
    • }
    • Application is oblivious of Object location
    • No separate calls to start and stop logging
    • Robust against exception
  • The Smartness …
    • It always points either to a valid allocated object or is NULL.
    • It deletes the object once there are no more references to it.
    • Fast. Preferably zero de-referencing and minimal manipulation overhead.
    • Raw pointers to be only explicitly converted into smart pointers. Easy search using grep is needed (it is unsafe).
    • It can be used with existing code.
  • The Smartness …
    • Programs that don’t do low-level stuff can be written exclusively using this pointer. No Raw pointers needed.
    • Thread-safe.
    • Exception safe.
    • It shouldn’t have problems with circular references.
  • Smart Pointers in C++ Storage Policy
  • 3–Way Storage Policy
    • The Storage Type (T*)
      • The type of pointee.
        • Specialized pointer types possible: FAR, NEAR.
      • By “default” – it is a raw pointer.
        • Other Smart Pointers possible – When layered
    • The Pointer Type (T*)
      • The type returned by operator–>
        • Can be different from the storage type if proxy objects are used.
    • The Reference Type (T&)
      • The type returned by operator*
  • Smart Pointers in C++ Ownership Management Policy
  • Ownership Management Policy
    • Smart pointers are about ownership of pointees
    • Exclusive Ownership
      • Every smart pointer has an exclusive ownership of the pointee
      • Three common flavors for this policy
        • Destructive Copy – std::auto_ptr
        • Deep Copy [Raw Pointers have Shallow Copy]
        • COW: Copy-on-Write
    • Shared Ownership
      • Ownership of the pointee is shared between Smart pointers
      • Track the Smart pointer references for lifetime
        • Reference Counting
        • Reference Linking
  • Ownership Policy: Destructive Copy
    • Exclusive Ownership Policy
    • Transfer ownership on copy
    • Source Smart Pointer in a copy is set to NULL
    • Available in C++ Standard Library
      • std::auto_ptr
    • Implemented in
      • Copy Constructor
      • operator=
  • Ownership Policy: Destructive Copy template <class T> class SmartPtr { public: SmartPtr(SmartPtr& src) { // Src ptr is not const pointee_ = src.pointee_; // Copy src.pointee_ = 0; // Remove ownership for src ptr } SmartPtr& operator=(SmartPtr& src) { // Src ptr is not const if (this != &src) { // Check & skip self-copy delete pointee_; // Release destination object pointee_ = src.pointee_; // Assignment src.pointee_ = 0; // Remove ownership for src ptr } return *this; // Return the assigned Smart Pointer } ... };
  • Ownership Policy: Destructive Copy – The Maelstrom Effect
    • Consider a call-by-value
    • Display acts like a maelstrom of smart pointers:
      • It sinks any smart pointer passed to it.
      • After Display(sp) is called, sp holds the null pointer.
    • Lesson – Pass Smart Pointers by Reference .
    • Smart pointers with destructive copy cannot usually be stored in containers and in general must be handled with care.
    void Display(SmartPtr<Something> sp); ... SmartPtr<Something> sp(new Something); Display(sp); // sinks sp STL Containers need FCO.
  • Ownership Policy: Destructive Copy – Advantages
    • Incurs almost no overhead.
    • Good at enforcing ownership transfer semantics.
      • Use the “maelstrom effect” to ensure that the function takes over the passed-in pointer.
    • Good as return values from functions.
      • The pointee object gets destroyed if the caller doesn't use the return value.
    • Excellent as stack variables in functions that have multiple return paths.
    • Available in the standard – std::auto_ptr.
      • Many programmers will get used to this behavior sooner or later.
  • Ownership Policy: Deep Copy
    • Exclusive Ownership Policy
      • Only one Smart Pointer for every pointee object
    • Copy the pointee Object when copying the Smart Pointer
      • Does it have any worth over call-by-value?
    • Implemented in
      • Copy Constructor
      • operator=
  • Ownership Policy: Deep Copy – Object Slicing
    • Naïve implementation
    • Does not work for polymorphic objects
      • Object Slicing: only ‘base’ part of a derived class object is copied
    template <class T> class SmartPtr { public: SmartPtr(const SmartPtr& other): pointee_(new T(*other.pointee_)) { ... } ... };
  • Ownership Policy: Deep Copy – Transport Polymorphic Objects
    • Smart implementation
    • Safe mechanism to transport polymorphic objects
    // Base class provides a prototype for Clone class AbstractBase { ... virtual Base* Clone() = 0; }; // Derived class implements Clone class Concrete : public AbstractBase { ... virtual Base* Clone() { return new Concrete(*this); } };
  • Ownership Policy: Copy-on-Write (COW)
    • Exclusive Ownership Policy
    • Allow multiple Smart pointers to point to the same pointee
    • Copy the pointee Object when it is written to (Lazy Evaluation)
    • Smart pointers are not the best place to implement COW
      • cannot differentiate between calls to const and non-const member functions of the pointee object.
    • COW is used in Meyers’ String Class.
  • Ownership Policy: Reference Counting
    • Shared Ownership Policy
    • Allow multiple Smart pointers to point to the same pointee
    • A count of the number of Smart pointers (references) pointing to a pointee is maintained
    • Destroy the pointee Object when the count equals 0
    • Do not keep: raw pointers and smart pointers to the same object.
  • Ownership Policy: Reference Counting
    • Variant Sub-Policies include
      • Non-Intrusive Counter
        • Multiple Raw Pointers per pointee
        • Single Raw Pointer per pointee
      • Intrusive Counter
    • Implemented in
      • Constructor
      • Copy Constructor
      • Destructor
      • operator=
  • Ownership Policy: Reference Counting: Non-Intrusive Counter
    • Additional count pointer per Smart Pointer.
    • Count in Free Store
    • Allocation of Count may be slow & wasteful because it is too small
  • Ownership Policy: Reference Counting: Non-Intrusive Counter
    • Additional count pointer removed.
    • But additional access level means slower speed.
  • Ownership Policy: Reference Counting: Intrusive Counter
    • Most optimized RC Smart Pointer
    • Cannot work for an already existing design
    • Used in COM
  • Ownership Policy: Reference Linking
    • Shared Ownership Policy
    • Allow multiple Smart pointers to point to the same pointee
    • All Smart pointers to a pointee are linked on a chain
      • The exact count is not maintained – only check if the chain is null
    • Destroy the pointee Object when the chain gets empty
    • Do not keep: raw pointers and smart pointers to the same object.
  • Ownership Policy: Reference Linking
    • Overhead of 2 additional pointers
    • Doubly-linked list for constant time:
      • Append,
      • Remove & Empty detection.
  • Ownership Policy: Reference Management – Disadvantage
    • Circular / Cyclic Reference
      • Object A holds a smart pointer to an object B. Object B holds a smart pointer to A. Forms a cyclic reference.
        • Typical for a Tree: Child & Parent pointers
      • Cyclic references go undetected
        • Both the two objects remain allocated forever
        • Resource Leak occurs.
      • The cycles can span multiple objects.
  • Ownership Policy: Cyclic Reference – Hack
    • The Hack
    • Use Smart pointer from Parent to Child.
      • “ Data Structure” Pointers
    • Use Raw pointer from Child to Parent.
      • “ Algorithm” Pointers
    Smart Pointers “own”; Raw Pointers “disowns”?
  • Ownership Policy: Cyclic Reference – Solution
    • Maintain two flavors of RC Smart Pointers
      • “ Strong” pointers that really link up the data structure (Child / Sibling Links). They behave like regular RC.
      • “ Weak” pointer for cross / back references in the data structure (Parent / Reverse Sibling Links)
    • Keep two reference counts:
      • One for total number of pointers, and
      • One for strong pointers.
    • While dereferencing a weak pointer, check the strong reference count.
      • If it is zero, return NULL. As if, the object is gone.
  • Smart Pointers in C++ Implicit Conversion
  • Implicit Conversion
    • Consider
    • User-Defined Conversion (cast)
    • User-unattended access to the raw pointer can defeat the purpose of the smart pointer
    // For maximum compatibility this should work void Fun(Something* p); ... SmartPtr<Something> sp(new Something); Fun(sp); // OK or error? template <class T> class SmartPtr { public: operator T*() // user-defined conversion to T* { return pointee_; } ... };
  • Implicit Conversion: The Pitfall
    • This compiles okay!!!
    • Ambiguity Injection solves …
    • Prefer Explicit Conversion over Implicit
      • Use GetImpl() & GetImplRef()
    // A gross semantic error that goes undetected at compile time SmartPtr<Something> sp; ... delete sp; // Compiler passes this by casting to raw pointer template <class T> class SmartPtr { public: operator T*() // User-defined conversion to T* { return pointee_; } operator void*() // Added conversion to void* { return pointee_; } ... }; “ When in doubt, use brute force. ” – Ken Thompson
  • Smart Pointers in C++ Null Tests
  • Null Tests
    • Expect the following to work?
    • Implicit conversion to:
      • T*
      • void *
    • Implicit conversion  Risky delete  Ambiguity Injection  Ambiguity causes compilation failures
    SmartPtr<Something> sp1, sp2; Something* p; ... if (sp1) // Test 1: direct test for non-null pointer ... if (!sp1) // Test 2: direct test for null pointer ... if (sp1 == 0) // Test 3: explicit test for null pointer ...
  • Null Tests
    • Overload operator!
    template <class T> class SmartPtr { public: // Returns true iff pointee is NULL bool operator!() { return pointee_ == 0; } }; if (sp1) // Rewrite as if (!!sp1) if (!sp1) // Works fine if (sp1 == 0) // Does not work
  • Smart Pointers in C++ Checking Policy
  • Checking Policy
    • Applications need various degrees of safety:
      • Computation-intensive – optimize for speed.
      • I/O intensive –allows better runtime checking.
    • Two common models:
      • Low safety / High speed (critical areas).
      • High safety / Lower speed.
    • Checking policy with smart pointers:
      • Checking Functions
        • Initialization Checking &
        • Checking before Dereferencing
      • Error Reporting
  • Checking Policy: Initialization Checking
    • Prohibit a Smart Pointer from being NULL
      • A Smart Pointer is always valid
      • Loses the ‘not-a-valid-pointer’ idiom
      • How would default constructor initialize raw pointer?
    template <class T> class SmartPtr { public: // Prohibit NULL for initialization SmartPtr(T* p): pointee_(p) { if (!p) throw NullPointerException(); } ... };
  • Checking Policy: Checking before Dereferencing
    • Dereferencing a null pointer is undefined!
    • Implemented in
      • Operator->
      • Operator*
    template <class T> class SmartPtr { public: T& operator*() const { // Dereferencing if (!pointee_) throw NullPointerException(); else return *pointee_; } T* operator->() const { // Indirection if (!pointee_) throw NullPointerException(); else return pointee_; } ... }; if (p) { /* Dereference & use p */ } else { /* Handle null pointer condition */ }
  • Checking Policy: Error Reporting
    • Throw an exception to report an error
    • Use ASSERT in debug build
      • Checking (debug) + Speed (release)
    • Lazy Initialization – construct when needed
      • Operator->
      • Operator*
    template <class T> class SmartPtr { public: T& operator*() { // Dereferencing. No Constant if (!pointee_) pointee_ = new T; return *pointee_; } T* operator->() { // Indirection. No Constant if (!pointee_) pointee_ = new T; return pointee_; } ... };
  • Smart Pointers in C++ Other Design Issues
  • What is a Smart Pointer?
    • Smart Pointer Operations
      • Construction , Copy Construction operator new
      • Destruction operator delete
      • De-referencing operator*
      • Indirection operator->
      • Assignment operator=
      • Null Test operator! ( operator == 0 )
      • Comparison operator== , operator!= , …
      • Cast operator(int) , operator(T*)
      • Address Of operator&
      • Address Arithmetic operator+ , operator- , operator++ , operator-- , operator+= , operator-=
      • Array operator new , operator delete , operator[]
  • Other Design Issues
    • Comparison of two Smart Pointers
      • Equality, Inequality, Ordering
    • Checking and Error Reporting
      • Initialization checking
      • Checking before dereference
    • const-ness
      • Smart Pointers to const and
      • const Smart Pointers
    • Arrays
    • Multi-Threading / Locks
      • Proxy Objects
  • Smart Pointers in C++ Performance Issues
  • Space Overhead in Smart Pointers 4 pointer_next *n+4 pointer_prev *n Reference Linking 4 counter RC: Intrusive 4 pointer +4 counter RC: Non-Intrusive (1) 4 pointer *n+4 counter RC: Non-Intrusive (n) <= (n-1)*sizeof(<Object>) COW (n-1)*sizeof(<Object>) Deep Copy Nil Destructive Copy Overhead Ownership
  • Smart Pointer Timing (GCC, MSVC)
    • Time in ns to acquire a pointer (default construction), perform n amortized copy operations on it & finally release it.
    • The allocation time for the contained pointer is not included, but the time for it's deallocation is.
    • A dumb pointer is a smart pointer that simply acquires and releases its contained pointer with no extra overhead. A raw pointer is a C pointer.
  • Smart Pointers in Practice A Few Examples
  • Smart Pointers in Practice
    • std::auto_ptr
      • Only Smart pointer in C++ standard library
      • Uses a Destructive Copy
      • Good for automatic (local) variables
      • Cannot be used in STL
        • Not Copy Constructible
        • Not Assignable
    “ Think of the Standard C++ auto_ptr as the Ford Escort of smart pointers: A simple general-purpose smart pointer that doesn't have all the gizmos and luxuries of special-purpose or high-performance smart pointers, but that does many common things well and is perfectly suitable for regular daily use. ” – C/C++ Users Jounral, October 1999.
  • Smart Pointers in Practice
    • Boost Library – shared_ptr
      • Well designed, Easy to use & Highly portable
      • Single-threaded
      • Shared Ownership
        • Reference Counted (non-intrusive)
      • Has specializations
        • scoped_ptr – Simple sole ownership of single objects. Noncopyable.
        • weak_ptr – Non-owning observers of an object owned by shared_ptr.
        • intrusive_ptr – Shared ownership of objects with an embedded reference count.
        • Array Versions
  • Smart Pointers in Practice
    • Component Object Model (COM)
      • Reference Counted Smart Pointer on Interfaces
        • A pointer to an array of function pointers
      • An implementation in C / C++ / VB …
      • Structured Lifetime Management with user cooperation
      • Addref() to increase reference count
        • Automatically called from QueryInterace() of the COM
      • Release() to decrease count
        • COM is unloaded when reference count falls to zero
  • std::auto_ptr The Smart Pointer in Standard Library
  • std::auto_ptr
    • The Philosophy
    • Destructive Copy – A Review
    • Standard Interface & Sample Implementation
    • Using Idioms
    • History
    • Portability
    • Pitfalls
  • std::auto_ptr
    • An auto_ptr is an object that acts just like a pointer, except it automatically deletes what it points to when it (the auto_ptr) is destroyed.
    “ Think of the Standard C++ auto_ptr as the Ford Escort of smart pointers: A simple general-purpose smart pointer that doesn't have all the gizmos and luxuries of special-purpose or high-performance smart pointers, but that does many common things well and is perfectly suitable for regular daily use. ” – C/C++ Users Jounral, October 1999.
  • std::auto_ptr
    • Storage Policy
      • Normal
    • Ownership Policy
      • Destructive Copy
    • Conversion Policy
      • Explicit for Raw Pointer
      • Implicit for compatible types (Base, Derived)
      • Implicit for auto_ptr reference
      • Null Test – Not provided
    • Checking Policy
      • None
  • std::auto_ptr
    • Good for automatic (local) variables
    • RAII – Resource Acquisition Is Initialization idiom
    • Selectively disallows “unwanted” operations
    • Lifetime Management
      • Automatically manages dynamically created objects
      • Exception Safe
    • Cannot be used in STL
      • Not Copy Constructible
      • Not Assignable
  • std::auto_ptr Standard Interface Sample Implementation
  • std::auto_ptr Interface
    • // auto_ptr class
    • template<class X> class auto_ptr {
    • private:
    • // A wrapper class for reference
    • // semantics with auto_ptr
    • template<class Y> struct auto_ptr_ref {};
    • // The raw pointer it holds
    • X* _ptr;
    • public:
    • // The type of the pointee
    • typedef X element_type;
  • std::auto_ptr Interface
    • explicit
    • auto_ptr(X* _p = 0) throw(); // Constructor
    • auto_ptr(auto_ptr& _a) throw(); // Copy Constructor
    • template<class Y> // Copy Compatible Type
    • auto_ptr(auto_ptr<Y>& _a) throw();
    • auto_ptr& operator=(auto_ptr& _a) throw() // Assignment
    • template<class Y> // Assignment Compatible Type
    • auto_ptr& operator=(auto_ptr<Y>& _a) throw();
    • ~auto_ptr(); // Destructor
  • std::auto_ptr Interface
    • // De-Reference
    • X& operator*() const throw();
    • // Indirection
    • X* operator->() const throw();
    • // Expose Raw Pointer
    • X* get() const throw();
    • // Relinquish Ownership
    • X* release() throw();
    • // Reset Ownership
    • void reset(X* _p = 0) throw();
  • std::auto_ptr Interface
    • // Copy from Reference Type
    • auto_ptr(auto_ptr_ref<X> _ref) throw();
    • // Cast to Compatible Reference Type
    • template<class Y>
    • operator auto_ptr_ref<Y>() throw();
    • // Cast to Compatible Type
    • template<class Y>
    • operator auto_ptr<Y>() throw();
    • };
  • std::auto_ptr Implementation
    • // De-Reference
    • X& operator*() const throw() { return *_ptr; }
    • // Indirection
    • X* operator->() const throw() { return _ptr; }
    • // Expose Raw Pointer
    • X* get() const throw() { return _ptr; }
  • std::auto_ptr Implementation
    • // Release Ownership
    • X* release() throw() {
    • X* _tmp = _ptr;
    • _ptr = 0;
    • return _tmp;
    • }
    • // Reset Ownership
    • void reset(X* _p = 0) throw() {
    • if (_p != _ptr) {
    • delete _ptr;
    • _ptr = _p;
    • }
    • }
  • std::auto_ptr Implementation
    • // Constructor
    • explicit auto_ptr(X* _p = 0) throw(): _ptr(_p) {}
    • // Copy Constructor
    • auto_ptr(auto_ptr& _a) throw(): _ptr(_a.release()) {}
    • // Copy Constructor Compatible Type
    • template<class Y> auto_ptr(auto_ptr<Y>& _a) throw(): _ptr(_a.release()) { }
    • // Assignment
    • auto_ptr& operator=(auto_ptr& _a) throw() {
    • reset(_a.release());
    • return *this;
    • }
  • std::auto_ptr Implementation
    • // Assignment Compatible Type
    • template<class Y>
    • auto_ptr& operator=(auto_ptr<Y>& _a) throw() {
    • reset(_a.release());
    • return *this;
    • }
    • // Destructor
    • ~auto_ptr() { delete _ptr; }
  • std::auto_ptr Implementation
    • // Convert an auto_ptr into and from an auto_ptr_ref
    • // automatically as needed.
    • // Copy from Reference
    • auto_ptr(auto_ptr_ref<X> _ref) throw():
    • _ptr(_ref._ptr) {}
    • // Cast to Reference Type
    • template<class Y> operator auto_ptr_ref<Y>() throw()
    • { return auto_ptr_ref<Y>(this->release()); }
    • // Cast to Compatible Type
    • template<class Y> operator auto_ptr<Y>() throw()
    • { return auto_ptr<Y>(this->release()); }
  • std::auto_ptr Using Idioms
  • Using std::auto_ptr – Safety
    • // Unsafe code void f() { T* pt(new T);
    • /*...more code...*/
    • delete pt;
    • }
    • // Safe code, with auto_ptr void f() {
    • auto_ptr<T> pt(new T);
    • /*...more code...*/
    • }
    • // pt's destructor is called as it goes out of
    • // scope - the object is deleted automatically
  • Using std::auto_ptr – const-ness
    • // Caveat: gets ownership of passed argument
    • template <class T> void dangerous_function(std::auto_ptr<T>);
    •  
    • // safe auto_ptr
    • const std::auto_ptr<int> p(new int);
    • // OK, change value to which p refers
    • *p = 42;
    • // COMPILE-TIME ERROR!
    • dangerous_function(p);                    
    Guard Maelstrom Effect
  • Using std::auto_ptr – Common Stuff
    • void g() {
    • T* pt1 = new T; // Here, we own the object
    • auto_ptr<T> pt2(pt1); // Pass ownership
    • // use the auto_ptr we'd use a simple pointer
    • *pt2 = 12; // Same as &quot;*pt1 = 12;“
    • pt2->SomeFunc(); // Same as &quot;pt1->SomeFunc();&quot;
    • assert(pt1 == pt2.get()); // Check pointer
    • T* pt3 = pt2.release(); // Take back ownership
    • delete pt3; // Delete the object ourselves
    • } // pt2 doesn't own any pointer, and so won't
    • // try to delete it... OK, no double delete
  • Using std::auto_ptr – reset()
    • void h() {
    • auto_ptr<T> pt(new T(1));
    • // deletes the first T that was
    • // allocated with &quot;new T(1)&quot;
    • pt.reset(new T(2));
    • } // finally, pt goes out of scope and
    • // the second T is also deleted
  • Using std::auto_ptr – Ownership
    • // Transferring ownership
    • void f() {
    • auto_ptr<T> pt1(new T);
    • auto_ptr<T> pt2; // A null pointer
    • pt1->DoSomething(); // OK
    • pt2 = pt1; // now pt2 owns the ptr,
    • // and pt1 does not
    • pt2->DoSomething(); // OK
    • pt1->DoSomething(); // error! a null pointer
    • } // as we go out of scope, pt2's destructor
    • // deletes the pointer, but pt1's does nothing
  • Using std::auto_ptr – Source
    • Source() allocates a new object and returns it to the caller in a completely safe way, by letting the caller assume ownership of the pointer.
    • Even if the caller ignores the return value the allocated object will always be safely deleted.
    • auto_ptr<T> Source() { return auto_ptr<T>(new Y); }
    • // Source could be a Class Factory
    • auto_ptr<X> pt(Source()); // takes ownership
    Resource creator
  • Using std::auto_ptr – Sink
    • Sink() takes an auto_ptr by value and therefore assumes ownership of it.
    • When Sink() is done, the deletion is performed as the local auto_ptr object goes out of scope (as long as Sink() itself hasn't handed off ownership to someone else).
    • The Sink() function below doesn't actually do anything with its parameter, so calling &quot;Sink( pt );&quot; is a fancy way of writing &quot;pt.reset(0);&quot;, but normally a sink function would do some work with the object before freeing it.
    • void Sink(auto_ptr<T> pt) {}
    Resource releaser
  • std::auto_ptr History
  • History of auto_ptr
    • Version 1:
      • Prior to March 1996.
      • Referred to as the CD-1 version, after the ISO draft.
    • Version 2:
      • From March 1996 until November 1997.
      • Referred to as the CD-2 version.
    • Version 3:
      • From November 1997.
      • Made to the final ISO/ANSI standard for C++.
      • Also known as the FDIS (&quot;Final Draft International Standard&quot;) version.
  • History of auto_ptr
    • Version 1:
      • Only one auto_ptr is allowed to point to an object.
      • Copying an auto_ptr sets its dumb pointer to null.
    • Version 2:
      • Multiple auto_ptrs may point to an object, but exactly one is designated the &quot;owner&quot;.
      • When the owning auto_ptr is destroyed, it deletes what it points to.
      • When non-owning auto_ptrs are destroyed, nothing happens to the object they point to.
      • Copying an auto_ptr transfers ownership.
    • Version 3:
      • Same as Version 1, but the interface was modified to prevent behavioral anomalies present in Version 1.
  • auto_ptr: Version 1
    • template<class T>
      • class auto_ptr {
      • public: explicit auto_ptr(T *p = 0);
      • template<class U> auto_ptr(auto_ptr<U>& rhs);
      • ~auto_ptr();
      • template<class U> auto_ptr<T>& operator=(auto_ptr<U>& rhs);
      • T& operator*() const;
      • T* operator->() const;
      • T* get() const;
      • T* release();
      • void reset(T *p = 0);
      • private: T *pointee;
    • };
    • Note:
    • No const on copy parameters
    • No throw();
  • auto_ptr: Version 1 – Shortcomings
    • Prevents any use of an auto_ptr returned from a function:
    • auto_ptr f(); // f returns an auto_ptr
    • auto_ptr p1(f()); // Error! can't copy an auto_ptr
    • // returned from a function
    • auto_ptr p2; p2 = f(); // Error! can't use an auto_ptr
    • // returned from a function as
    • // the source of an assignment
    • Why?
      • Objects returned from functions are temporary objects, and temporary objects can't be bound to reference parameters unless the parameters are references to const objects.
      • auto_ptr 's copy constructor and assignment operator take reference-to-non-const parameters
  • auto_ptr: Version 2
    • template<class X>
      • class auto_ptr {
        • mutable bool owner;
        • X* px;
        • template<class Y> friend class auto_ptr;
      • public:
        • explicit auto_ptr(X* p=0) ;
        • template<class Y> auto_ptr(const auto_ptr<Y>& r);
        • template<class Y> auto_ptr&
        • operator=(const auto_ptr<Y>& r)
        • ~auto_ptr();
        • X& operator*() const;
        • X* operator->() const;
        • X* get() const;
        • X* release() const;
      • }
    • const introduced in Copy
    • reset() dropped
    • A bool member to track ownership
  • auto_ptr: Version 2
    • template<class Y> auto_ptr(const auto_ptr<Y>& r) : owner(r.owner), px(r.release()) {}
    • template<class Y>
    • auto_ptr& operator=(const auto_ptr<Y>& r) {
    • if ((void*)&r != (void*)this) {
    • if (owner) delete px;
    • owner = r.owner;
    • px = r.release();
    • }
    • return *this;
    • }
    • ~auto_ptr() { if (owner) delete px; }
    • X* release() const { owner = 0; return px; } };
    These methods matter!
  • auto_ptr: Version 2 – Shortcomings
    • Destructive Copy Semantics lost
      • Unique ownership retained
      • Double Deletion Error protected
    • Potential Dangling Pointer
    • Not safe for const auto_ptr
      • Maelstrom Effect returns
  • auto_ptr: Version 3
    • namespace std {
    • template<class X> class auto_ptr {
    • template<class Y> struct auto_ptr_ref {};
    • public:
      • typedef X element_type;
      • explicit auto_ptr(X* p=0) throw();
      • auto_ptr(auto_ptr&) throw();
      • template<class Y> auto_ptr(auto_ptr<Y>&) throw();
      • auto_ptr& operator=(auto_ptr&) throw()
      • template<class Y> auto_ptr& operator=(auto_ptr<Y>&) throw();
      • ~auto_ptr() throw();
      • X& operator*() const throw();
      • X* operator->() const throw();
      • X* get() const throw();
      • X* release() throw();
      • void reset(X* p=0) throw();
      • auto_ptr(auto_ptr_ref<X>) throw();
      • template<class Y> operator auto_ptr_ref<Y>() throw();
      • template<class Y> operator auto_ptr<Y>() throw(); }; }
    Colvin-Gibbons Trick
  • auto_ptr: Version 3 – Advantages
    • Clean handling of function return value
      • Direct Initialization: Same Type
      • auto_ptr<int> source();
      • auto_ptr<int> p(source());
      • // Constructor: auto_ptr<int>::auto_ptr(auto_ptr_ref<int>);
      • // Conversion:
      • auto_ptr<int>::operator auto_ptr_ref<int>();
  • auto_ptr: Version 3 – Advantages
    • Clean handling of function return value
      • Copy Initialization: Same Type
      • auto_ptr<int> source();
      • void sink(auto_ptr<int>);
      • main() { sink(source()); }
      • // Constructor: auto_ptr<int>::auto_ptr(auto_ptr_ref<int>);
      • // Conversion:
      • auto_ptr<int>::operator auto_ptr_ref<int>();
  • auto_ptr: Version 3 – Advantages
    • Clean handling of function return value
      • Direct Initialization: Base-from-Derived Type
      • struct Base{};
      • struct Derived : Base{};
      • auto_ptr<Derived> source();
      • auto_ptr<Base> p(source());
      • // Constructor: auto_ptr<Base>::auto_ptr(auto_ptr_ref<Base>);
      • // Conversion:
      • auto_ptr<Derived>::operator auto_ptr_ref<Base>();
  • auto_ptr: Version 3 – Advantages
    • Clean handling of function return value
      • Copy Initialization: Base-from-Derived Type
      • struct Base {};
      • struct Derived : Base {};
      • auto_ptr<Derived> source();
      • void sink(auto_ptr<Base>);
      • main() { sink(source()); }
      • // Constructor: auto_ptr<Base>::auto_ptr<Derived>(auto_ptr<Derived> &);
      • // Conversion:
      • auto_ptr<Derived>::operator auto_ptr<Base>();
  • auto_ptr: Version 3 – Advantages
    • Complete Destructive Copy Semantics
  • std::auto_ptr Portability
  • What is your auto_ptr?
    • Check with the compiler:
      • Look for <memory> in standard library
    • Sample Variations
      • GCC 3.4 & VC++ 7.1 implements Version 3
      • VC++ 6.0 implements Version 2
    • Member Function Template
      • Support is still limited between compilers
      • Customizes auto_ptr to eliminate member function template
      • Sample: VC++ 6.0
    • Consider having your own auto_ptr
  • std::auto_ptr Pitfalls
  • auto_arrays!
    • Do not use auto_ptr with arrays:
    • #include <iostream>
    • #include <memory>
    • #include <string>
    • using namespace std;
    • int c = 0;
    • class X {
    • public:
    • X(): s(&quot;1234567890&quot;) { ++c; }
    • ~X() { --c; }
    • string s;
    • };
    • template<typename T> void f(size_t n) {
    • {
    • auto_ptr<T> p1(new T);
    • auto_ptr<T> p2(new T[n]);
    • }
    • cout << c << &quot; &quot;; // report # of X objects that currently exist
    • }
    • void main() { while (true) { f<X>(100); } }
  • auto_arrays! Survival
    • Always match new – delete and new[] – delete[] .
    • Use vector<T> in STL
  • Coping with COAP
    • Never create c ontainers o f a uto_ p tr’s (COAP):
      • STL Containers need an FCO copy semantics – auto_ptr does not support that
      • Suppose sort() below is implemented as quicksort. The moment the “pivot element” is copied in a temporary it is lost from seqs!
      • bool CompareSequenceAP(
      • const auto_ptr<Sequence>& lhs,
      • const auto_ptr<Sequence>& rhs)
      • { return *lhs < *rhs; } // operator< exists in Sequence
      • vector<auto_ptr<Sequence> > seqs;
      • sort(seqs.begin(), seqs.end(), CompareSequenceAP);
      • C++ Standard prohibits such situations in compilation (Recall, auto_ptr copies take reference-to-non-const).
  • Coping with COAP: Survival
    • Use other (non-destructive copy) Smart Pointers with STL Containers
  • Smart Pointers in C++ References & Credits
  • References: Books
    • Effective C++ by Scott Meyers
    • More Effective C++: 35 New Ways to Improve Your Programs and Designs – Scott Meyers , Pearson Education & AWP 1999
    • Modern C++ Design: Generic Programming & Design Pattern Applied – Andrei Alexandrescu , Pearson Education 2001
    • C++ Templates: The Complete Guide – David Vandevoorde & Nicolai M. Josuttis , Pearson Education & AWP 2003
    • Exceptional C++ by Herb Sutter
    • More Exceptional C++ by Herb Sutter
    • The C++ Programming Language by Bjarne Stroustrup
  • References: Papers
    • A static analyzer for finding dynamic programming errors - William R. Bush, Jonathan D. Pincus and David J. Sielaff , Software Practice Experience 2000; 30:775–802
      • Used for PREfix simulation results on Pointer Hazards
  • References: Online Help
    • MSVC 6.0
    • MSVC 7.1
    • GCC
  • References: Codes
    • <memory> header of Your Compiler
  • References: Code URLs
    • CodeProject – http://www.codeproject.com
      • Smart Pointers
        • A Simple Smart Pointer
        • A Smart Pointer Capable of Object Level Thread
        • Smart Pointers to boost your code
        • The Fastest Smart Pointer in the West
        • The Safest Smart Pointer of the East
        • A generic C++ template class to implement a Smart Pointer
        • A COM Smart Pointer
      • Pointers (General)
        • How to do pointers in VB?
        • Pointers in Visual Basic using Undocumented Functions
      • Garbage Collectors
        • A garbage collection framework for C++
        • A garbage collection framework for C++ - Part II
        • Synchronization and Reference Counting Garbage Collection
    • Boost Library – http://www.boost.org
      • shared_ptr and its variants
      • Smart Pointer Timing
  • References: Knowledge URLs
    • “ Informal Language Comparison Chart(s)” – www.smallscript.org/Language%20Comparison%20Chart.asp
    • “ Pointer Basics” – http://cslibrary.stanford.edu/106/
    • “ Pointers, References & Values” – www.goingware.com
    • “ Using auto_ptr Effectively” – www.cuj.com , October 1999 and www.gotw.ca/publications/using_auto_ptr_effectively.htm
    • “ Smart pointer templates in C++” by David Harvey – www.davethehat.com/articles/smartp.htm
    • “ C++ Without Memory Errors” by Dejan Jelović – www.jelovic.com/articles/cpp_without_memory_errors_slides.htm
    • “ Smart Pointer Thread Safety” by Dejan Jelović – www.jelovic.com/articles/smart_pointer_thread_safety.htm
    • “ The New C++: Smart(er) Pointers” by Herb Sutter – www.cuj.com , August 2000.
    • “ Programming Language Comparion” by Jason Voegele – www.jvoegele.com/software/langcomp.html
    • “ The case against C” by P. J. Moylan – www.modulaware.com/mdlt35.htm
    • “ Smart Pointers - What, Why, Which?” by Yonat Sharon – http://ootips.org/yonat/4dev/smart-pointers.html
    • RAII Idiom and Managed C++ http:// www.codeproject.com/managedcpp/managedraii.asp  
    • GNU GCC 3.4
    • http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/memory-source.html
    • http://www.cs.huji.ac.il/~etsman/Docs/gcc-3.4-base/libstdc++/html_user/debug_8h-source.html
    • MSDN Library
    • http:// msdn.microsoft.com
  • Credits / Acknowledgements
    • Reena
      • helped in desk editing this presentation.
    • Scott Meyers
      • helped by providing pointers to various smart pointer resources.
    • Shyamal
      • for being a patient audience to my early stages of development of understanding
  • Thank You Don’t Beware of Pointers – Just Be Aware of Smart Pointers
  • std::tr1::shared_ptr std::tr1::weak_ptr Additional Smart Pointers in TR1 Standard Library of C++ ISO/IEC PDTR 19768. Doc No: N1745=05-0005. Date: 2005-01-17
  • Motivation for a Shared-Ownership Smart Pointer
    • Is a reasonable default choice for many (or even most) smart pointer needs
      • consistent with the spirit of the Standard Library.
    • Can be used in Standard Library containers
      • filling a major embarrassing gap in the current Standard Library.
    • Has been reinvented thousands of times
    • Is very hard to specify and implement correctly, particularly as regards
      • exception safety,
      • thread safety, and
      • weak pointers.
  • Motivation for the shared_ptr (Shared-Ownership)
    • Has the same object type regardless of features used
      • greatly facilitating interoperability between libraries, including third-party libraries.
    • Supports custom deallocators
      • allowing user-specified memory policies and extending management to a wide range of object types, such as COM objects.
    • Supports weak pointers
      • allowing cycle breaking and supporting observer applications such as caches.
    • Delivers exceptional expressive power without additional template parameterization
      • easing use by novices and experts alike.
    • Supports encapsulation and implementation hiding via
      • the ability to safely use incomplete classes,
      • protected non-virtual base destructors, and
      • the ability to hide allocation details.
  • Motivation for the shared_ptr (Shared-Ownership)
    • &quot;Just works&quot; in numerous tricky situations such as
      • calling the right destructor and crossing load-unit/heap boundaries.
    • Requires no language support.
    • Does not prevent users or the Standard Library itself from later adding other smart pointers
      • to meet additional needs.
    • Allows several implementation techniques
      • leaving implementers room for tradeoffs.
    • Reflects existing practice with a decade of refinement and use
      • including many non-obvious enhancements.
    • Is widely recommended
      • in books, magazine articles, and newsgroup postings
      • by both C++ experts and everyday users.
  • Motivation for the weak_ptr (Shared-Ownership-Observer)
    • Supports data structures with cyclic pointers
      • either weak_ptr or shared_ptr covers all important shared-ownership use cases.
    • Supports observer idioms such as caches.
      • Allows functions or classes to keep references to objects without affecting their lifetime.
    • Replaces unsafe uses of raw pointers
      • eliminating the possibility of following a dangling pointer.
    • Is very hard to specify and implement correctly.
    • Reflects existing practice with a decade of refinement and use.
  • Implementation Difficulty of Shared-Ownership Smart Pointer
    • Example 1:
      • shared_ptr<X> p(new X);
    • It is very common for even expert implementations to leak the X object when the smart pointer constructor throws an exception.
  • Implementation Difficulty of Shared-Ownership Smart Pointer
    • Example 2:
      • p.reset(new X);
    • The behavior when reset throws should be to delete the X object, and have no other effects, i.e. p must be left unchanged.
  • Implementation Difficulty of Shared-Ownership Smart Pointer
    • Example 3: (Boost's shared_ptr_test.cpp)
      • struct X { boost::shared_ptr<X> next; };
      • void test()
      • {
        • boost::shared_ptr<X> p(new X);
        • p->next = boost::shared_ptr<X>(new X);
        • p = p->next;
        • BOOST_TEST(!p->next);
      • }
    • Surprisingly many experts get this wrong.
  • Additional Implementation Difficulty of weak_ptr
    • The stored pointer in a weak_ptr can be
      • invalidated literally at any time; even in strictly single threaded and synchronous programs it is possible for the code to call a library that calls back a routine invalidating a weak_ptr .
    • The weak_ptr implementation must take care not to access the stored pointer value after the weak_ptr has expired .
      • Note: The value of a pointer referring to deallocated storage is indeterminate.
    • weak_ptr interface should protect users from
      • accidentally accessing a pointer to deallocated storage.
  • Impact on the Standard
    • A pure library extension.
    • Changes to an existing header, <memory>,
      • does not require changes to any standard classes or functions and
      • does not require changes to any of the standard requirement tables.
    • Does not require any changes in the core language, and is implemented in standard C++.
    • Does not depend on any other library extensions.
  • Design Decisions
    • General Principles
    • shared_ptr
    • weak_ptr
    • enable_shared_from_this
    • Size and Performance
    • Alternatives
  • Design Decisions: General Principles
    • &quot;As Close to Raw Pointers as Possible, but no Closer&quot;
    • &quot;Just Do the Right Thing&quot;
    • No Extra Parameters
    • The &quot;Shares Ownership with&quot; Equivalence Relation
    • The &quot;Empty Pointer&quot; Concept
  • As Close to Raw Pointers as Possible’ but no close
    • Interesting Properties of Raw Pointers:
      • Copy
      • Assign
      • Pass by value
      • Return by value
      • Destroy a pointer to an incomplete type.
      • Refer to any object's address using a pointer to void.
      • Pointers to derived classes are implicitly convertible to pointers to base classes
      • Use static_cast or dynamic_cast to perform the opposite conversion.
    • The two main problems are:
      • The need for manual resource management and
      • The possibility of accessing an invalid (dangling) pointer.
  • As Close to Raw Pointers as Possible’ but no Closer
    • shared_ptr and weak_ptr fully support
      • incomplete types,
      • cv-qualified types,
      • void as a template parameter, and
      • derived-to-base implicit conversions.
    • shared_ptr supports
      • static cast,
      • dynamic casts, and
      • will automatically delete (or otherwise release) the object it owns when the last shared_ptr instance is destroyed.
    • weak_ptr eliminates
      • the possibility of accessing a dangling pointer.
  • Just Do the Right Thing
    • Consider the scenario:
      • A shared_ptr can be created in a shared library and then
      • destroyed by the application.
      • By using implicit conversions, the last shared_ptr instance to an object may have a template parameter
        • void,
        • a base with an inaccessible or non-virtual destructor, or
        • an incomplete type.
    • What should happen during destructions?
      • The implementation should invoke the proper destructor or operator delete.
    • The information necessary to properly destroy the managed object is fully captured at the point where the smart pointer is constructed.
  • No Extra Parameter
    • The proposed smart pointers have a single template parameter, the type of the pointee.
    • Avoid additional parameters to ensure
      • interoperability between libraries from different authors, and
      • makes shared_ptr easier to use, teach and recommend.
  • “ Shares Ownership With” is an Equivalence Relation
    • &quot; p shares ownership with q &quot; to indicate that
      • p and q originated from the same smart pointer and
      • p and q own the same object.
    • &quot; Shares ownership with &quot; is an equivalence relation.
      • reflexive
        • p shares ownership with p
      • commutative
        • if p shares ownership with q , q also shares ownership with p
      • transitive
        • if p shares ownership with q and q shares ownership with r , p shares ownership with r .
  • “ Shares Ownership With” is an Equivalence Relation
    • This relation divides all non- empty smart pointers into equivalence classes.
    • The number of shared_ptr instances in p 's equivalence class can be obtained using p.use_count().
    • The last shared_ptr instance in a given equivalence class is responsible for destroying the owned object.
    • Implementations
      • Counted:
        • Two smart pointers share ownership when they share the same reference count.
      • Linked List:
        • Two smart pointers share ownership when they are part of the same list.
  • The “Empty Pointer” Concept
    • A smart pointer is called empty if it is
      • It is Default-constructed, or if
      • Its instances that have been reset()
    • Needed for
      • nothrow guarantee for
        • shared_ptr::shared_ptr(),
        • shared_ptr::reset(),
        • weak_ptr::weak_ptr(), and
        • weak_ptr::reset().
      • p.reset() used as delete p for raw pointers
        • need guarantee that this operation doesn't throw.
  • The “Empty Pointer” Concept
    • Strategy to guarantee nothrow
      • default constructors and reset() allowed to skip the allocation for tracking ownership
      • produce empty smart pointers that do not track ownership.
  • The “Empty Pointer” Concept
    • Implementation Strategy 1
      • Reuse one or more statically allocated reference counts for default-constructed pointer instances.
      • empty pointers, then, represent one or more equivalence classes under the ownership equivalence relation
      • use_count() can return &quot;realistic&quot; values that increase and decrease as additional empty pointers are created or destroyed.
  • The “Empty Pointer” Concept
    • Implementation Strategy 2 (Boost)
      • Do not allocate a reference count at all for empty pointers
      • Use a NULL pointer to count as an &quot; empty mark&quot;.
      • empty pointers have a constant use_count()
        • zero in Boost
      • empty pointers returning zero from use_count(), eliminates nearly all of the unspecified behavior.
  • The “Empty Pointer” Concept
    • Consider
      • int main() {
        • try {
          • shared_ptr<int> sp0;
          • weak_ptr<int> wp(sp0);
          • shared_ptr<int> sp(wp);
          • cout << &quot;Done &quot;;
        • }
        • catch (exception const & e)
        • { cerr << e.what() << ' '; }
      • }
    • Strategy #1 prints “Done”
    • Strategy #2 throws std::tr1::bad_weak_ptr
  • Design Decisions: shared_ptr
    • Pointer Constructor
    • Deleter Constructor
    • weak_ptr Constructor
    • std::auto_ptr Constructor
    • Assignment and reset
    • operator->
    • use_count and unique
    • Conversion Operator
    • operator<
    • operator<<
    • Casts
    • get_deleter
  • Design Decisions: weak_ptr
    • Default Constructor
    • Converting Constructor
    • lock
  • Design Decisions: enable_shared_from_this
  • Design Decisions: Size & Performance
    • Memory Footprint
    • Construction Performance
    • Copy Performance
  • Design Decisions: Alternatives
    • Policy Based Smart Pointers
    • Garbage Collection
  • Incomplete Type
    • An incomplete type is a type that describes an identifier but lacks information needed to determine the size of the identifier.
    • The following are incomplete types:
      • Type void
      • Array of unknown size
      • Arrays of elements that are of incomplete type
      • Structure, union, or enumerations that have no definition
      • Pointers to class types that are declared but not defined
      • Classes that are declared but not defined
    • void is an incomplete type that cannot be completed.
    • Incomplete types must be completed before being used to declare an object.
    • A pointer to an incomplete type can be defined.
  • Smart Pointer Classes in <memory>
    • In namespace std
      • template<class T> class auto_ptr;
      • As already in the Standard
    • In namespace std::tr1
      • class bad_weak_ptr;
      • template<class T> class shared_ptr;
      • template<class T> class weak_ptr;
      • These are propose additions
  • class bad_weak_ptr
    • namespace std {
    • namespace tr1 {
      • class bad_weak_ptr: public std::exception {
      • public:
      • bad_weak_ptr();
      • };
    • } // namespace tr1
    • } // namespace std
    • An exception of type bad_weak_ptr is thrown by the shared_ptr constructor taking a weak_ptr.
    • Postconditions: what() returns &quot;tr1::bad_weak_ptr&quot;.
    • Throws: nothing.
  • class shared_ptr
    • namespace std {
    • namespace tr1 {
    • template<class T> class shared_ptr {
    • public:
    • typedef T element_type;
    • // [2.2.3.1] constructors
    • shared_ptr();
    • template<class Y> explicit shared_ptr(Y * p);
    • template<class Y, class D> shared_ptr(Y * p, D d);
    • shared_ptr(shared_ptr const& r);
    • template<class Y> shared_ptr(shared_ptr<Y> const& r);
    • template<class Y> explicit
    • shared_ptr(weak_ptr<Y> const& r);
    • template<class Y> explicit shared_ptr(auto_ptr<Y>& r);
  • class shared_ptr
    • // [2.2.3.2] destructor
    • ~shared_ptr();
    • // [2.2.3.3] assignment
    • shared_ptr& operator=(shared_ptr const& r);
    • template<class Y> shared_ptr& operator=
    • (shared_ptr<Y> const& r);
    • template<class Y> shared_ptr& operator=
    • (auto_ptr<Y>& r);
    • // [2.2.3.4] modifiers
    • void swap(shared_ptr& r);
    • void reset();
    • template<class Y> void reset(Y * p);
    • template<class Y, class D> void reset(Y * p, D d);
  • class shared_ptr
    • // [2.2.3.5] observers
    • T* get() const;
    • T& operator*() const;
    • T* operator->() const;
    • long use_count() const;
    • bool unique() const;
    • operator unspecified-bool-type () const;
    • }; // template<class T> class shared_ptr
  • class shared_ptr
    • // [2.2.3.6] shared_ptr comparisons
    • template<class T, class U> bool operator==
    • (shared_ptr<T> const& a, shared_ptr<U> const& b);
    • template<class T, class U> bool operator!=
    • (shared_ptr<T> const& a, shared_ptr<U> const& b);
    • template<class T, class U> bool operator<
    • (shared_ptr<T> const& a, shared_ptr<U> const& b);
    • // [2.2.3.7] shared_ptr I/O
    • template<class E, class T, class Y>
    • basic_ostream<E, T>& operator<< (basic_ostream<E, T>& os, shared_ptr<Y> const& p);
    • // [2.2.3.8] shared_ptr specialized algorithms
    • template<class T> void swap(shared_ptr<T>& a, shared_ptr<T>& b);
  • class shared_ptr
    • // [2.2.3.9] shared_ptr casts
    • template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U> const& r);
    • template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const& r);
    • template<class T, class U> shared_ptr<T> const_pointer_cast(shared_ptr<U> const& r);
    • // [2.2.3.10] shared_ptr get_deleter
    • template<class D, class T> D * get_deleter(shared_ptr<T> const& p);
    • } // namespace tr1
    • } // namespace std
  • Design Decisions
    • A. General Principles
      • 1. &quot;As Close to Raw Pointers as Possible, but no Closer&quot;
      • 2. &quot;Just Do the Right Thing&quot;
      • 3. No Extra Parameters
      • 4. The &quot;Shares Ownership with&quot; Equivalence Relation
      • 5. The &quot;Empty Pointer&quot; Concept
    • B. shared_ptr
      • 1. Pointer Constructor
      • 2. Deleter Constructor
      • 3. weak_ptr Constructor
      • 4. std::auto_ptr Constructor
      • 5. Assignment and reset
      • 6. operator->
      • 7. use_count and unique
      • 8. Conversion Operator
      • 9. operator<
      • 10. operator<<
      • 11. Casts
      • 12. get_deleter
    • C. weak_ptr
      • 1. Default Constructor
      • 2. Converting Constructor
      • 3. lock
    • D. enable_shared_from_this
    • E. Size and Performance
      • 1. Memory Footprint
      • 2. Construction Performance
      • 3. Copy Performance
    • F. Alternatives
      • 1. Policy Based Smart Pointers
      • 2. Garbage Collection