KEMBAR78
Beware of Pointers | PPT
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\n&quot;;  }  catch (exception const & e)  { cerr << e.what() << '\n'; }  } 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

Beware of Pointers

  • 1.
    October 28, November4, December 2, 2005 Beware of Pointers! Dr. Partha Pratim Das Interra Systems (India) Pvt. Ltd. Resource Management Series
  • 2.
    Resource Management Bewareof 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
  • 3.
    Motivation Imbibe aculture 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
  • 4.
    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
  • 5.
    Agenda Smart Pointersin 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”
  • 6.
    Agenda std::auto_ptr The Philosophy Standard Interface & Sample Implementation Using Idioms History Portability Pitfalls References & Credits
  • 7.
    Raw Pointers ARaw Deal?
  • 8.
    What is aRaw 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++
  • 9.
    What is aRaw 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[]
  • 10.
    What is aRaw 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
  • 11.
    Ownership Issue ofPointers Ownership Issue – ASSIGN problem Memory Leaks! // Create ownership MyClass *p = new MyClass; // Lose ownership p = 0;
  • 12.
    Ownership Issue ofPointers 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;
  • 13.
    Ownership Issue ofPointers 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; }
  • 14.
    Ownership Issue ofPointers 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; }
  • 15.
    Ownership Issue ofPointers 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; }
  • 16.
    Pointer Hazards Pointerissues 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
  • 17.
    Pointer Hazards: PREfixSimulation Results
  • 18.
    A Pointer-free WorldReality or Utopia?
  • 19.
    How to dealwith 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
  • 20.
    Pointers vis-à-vis ReferenceUse ‘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
  • 21.
    Pointers-free Languages Whatis 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
  • 22.
    Pointers-free Languages FortranUse arrays to link VB / VB.Net Use Win32 API / Un-documented Functions to create pointers (link data structures)
  • 23.
    Pointers-free Languages JavaInternally 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 )
  • 24.
    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 …
  • 25.
    Pointers-free Languages DProgramming 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
  • 26.
    Pointers-free Languages SmallTalkEiffel ( 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
  • 27.
    Smart Pointers inC++ The Smartness …
  • 28.
    What is SmartPointer? 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
  • 29.
    What is SmartPointer? 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
  • 30.
    A Simple SmartPointer 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 };
  • 31.
    A Smart Pointermimics 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();
  • 32.
    Smart Pointer MemberFunctions 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);
  • 33.
    A Smart PointerUse-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?
  • 34.
    A Smart PointerUse-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 };
  • 35.
    A Smart PointerUse-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(); };
  • 36.
    A Smart PointerUse-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
  • 37.
    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.
  • 38.
    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.
  • 39.
    Smart Pointers inC++ Storage Policy
  • 40.
    3–Way Storage PolicyThe 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*
  • 41.
    Smart Pointers inC++ Ownership Management Policy
  • 42.
    Ownership Management PolicySmart 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
  • 43.
    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=
  • 44.
    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 } ... };
  • 45.
    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.
  • 46.
    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.
  • 47.
    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=
  • 48.
    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_)) { ... } ... };
  • 49.
    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); } };
  • 50.
    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.
  • 51.
    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.
  • 52.
    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=
  • 53.
    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
  • 54.
    Ownership Policy: Reference Counting: Non-Intrusive Counter Additional count pointer removed. But additional access level means slower speed.
  • 55.
    Ownership Policy: Reference Counting: Intrusive Counter Most optimized RC Smart Pointer Cannot work for an already existing design Used in COM
  • 56.
    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.
  • 57.
    Ownership Policy: Reference Linking Overhead of 2 additional pointers Doubly-linked list for constant time: Append, Remove & Empty detection.
  • 58.
    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.
  • 59.
    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”?
  • 60.
    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.
  • 61.
    Smart Pointers inC++ Implicit Conversion
  • 62.
    Implicit Conversion ConsiderUser-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_; } ... };
  • 63.
    Implicit Conversion: ThePitfall 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
  • 64.
    Smart Pointers inC++ Null Tests
  • 65.
    Null Tests Expectthe 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 ...
  • 66.
    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
  • 67.
    Smart Pointers inC++ Checking Policy
  • 68.
    Checking Policy Applicationsneed 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
  • 69.
    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(); } ... };
  • 70.
    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 */ }
  • 71.
    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_; } ... };
  • 72.
    Smart Pointers inC++ Other Design Issues
  • 73.
    What is aSmart 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[]
  • 74.
    Other Design IssuesComparison 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
  • 75.
    Smart Pointers inC++ Performance Issues
  • 76.
    Space Overhead inSmart 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
  • 77.
    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.
  • 78.
    Smart Pointers inPractice A Few Examples
  • 79.
    Smart Pointers inPractice 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.
  • 80.
    Smart Pointers inPractice 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
  • 81.
    Smart Pointers inPractice 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
  • 82.
    std::auto_ptr The SmartPointer in Standard Library
  • 83.
    std::auto_ptr The PhilosophyDestructive Copy – A Review Standard Interface & Sample Implementation Using Idioms History Portability Pitfalls
  • 84.
    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.
  • 85.
    std::auto_ptr Storage PolicyNormal 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
  • 86.
    std::auto_ptr Good forautomatic (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
  • 87.
    std::auto_ptr Standard InterfaceSample Implementation
  • 88.
    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;
  • 89.
    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
  • 90.
    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();
  • 91.
    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(); };
  • 92.
    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; }
  • 93.
    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; } }
  • 94.
    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; }
  • 95.
    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; }
  • 96.
    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()); }
  • 97.
  • 98.
    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
  • 99.
    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
  • 100.
    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
  • 101.
    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
  • 102.
    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
  • 103.
    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
  • 104.
    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
  • 105.
  • 106.
    History of auto_ptrVersion 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.
  • 107.
    History of auto_ptrVersion 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.
  • 108.
    auto_ptr: Version 1template<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();
  • 109.
    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
  • 110.
    auto_ptr: Version 2template<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
  • 111.
    auto_ptr: Version 2template<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!
  • 112.
    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
  • 113.
    auto_ptr: Version 3namespace 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
  • 114.
    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>();
  • 115.
    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>();
  • 116.
    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>();
  • 117.
    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>();
  • 118.
    auto_ptr: Version 3– Advantages Complete Destructive Copy Semantics
  • 119.
  • 120.
    What is yourauto_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
  • 121.
  • 122.
    auto_arrays! Do notuse 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); } }
  • 123.
    auto_arrays! Survival Alwaysmatch new – delete and new[] – delete[] . Use vector<T> in STL
  • 124.
    Coping with COAPNever 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).
  • 125.
    Coping with COAP:Survival Use other (non-destructive copy) Smart Pointers with STL Containers
  • 126.
    Smart Pointers inC++ References & Credits
  • 127.
    References: Books EffectiveC++ 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
  • 128.
    References: Papers Astatic 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
  • 129.
    References: Online HelpMSVC 6.0 MSVC 7.1 GCC
  • 130.
    References: Codes <memory> header of Your Compiler
  • 131.
    References: Code URLsCodeProject – 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
  • 132.
    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
  • 133.
    Credits / AcknowledgementsReena 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
  • 134.
    Thank You Don’tBeware of Pointers – Just Be Aware of Smart Pointers
  • 135.
    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
  • 136.
    Motivation for aShared-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.
  • 137.
    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.
  • 138.
    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.
  • 139.
    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.
  • 140.
    Implementation Difficulty ofShared-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.
  • 141.
    Implementation Difficulty ofShared-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.
  • 142.
    Implementation Difficulty ofShared-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.
  • 143.
    Additional Implementation Difficultyof 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.
  • 144.
    Impact on theStandard 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.
  • 145.
    Design Decisions GeneralPrinciples shared_ptr weak_ptr enable_shared_from_this Size and Performance Alternatives
  • 146.
    Design Decisions: GeneralPrinciples &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
  • 147.
    As Close toRaw 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.
  • 148.
    As Close toRaw 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.
  • 149.
    Just Do theRight 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.
  • 150.
    No Extra ParameterThe 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.
  • 151.
    “ Shares OwnershipWith” 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 .
  • 152.
    “ Shares OwnershipWith” 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.
  • 153.
    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.
  • 154.
    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.
  • 155.
    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.
  • 156.
    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.
  • 157.
    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\n&quot;; } catch (exception const & e) { cerr << e.what() << '\n'; } } Strategy #1 prints “Done” Strategy #2 throws std::tr1::bad_weak_ptr
  • 158.
    Design Decisions: shared_ptrPointer 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
  • 159.
    Design Decisions: weak_ptrDefault Constructor Converting Constructor lock
  • 160.
    Design Decisions: enable_shared_from_this
  • 161.
    Design Decisions: Size & Performance Memory Footprint Construction Performance Copy Performance
  • 162.
    Design Decisions: AlternativesPolicy Based Smart Pointers Garbage Collection
  • 163.
    Incomplete Type Anincomplete 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.
  • 164.
    Smart Pointer Classesin <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
  • 165.
    class bad_weak_ptr namespacestd { 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.
  • 166.
    class shared_ptr namespacestd { 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);
  • 167.
    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);
  • 168.
    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
  • 169.
    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);
  • 170.
    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
  • 171.
    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

Editor's Notes

  • #11 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 &amp;quot; second-class objects &amp;quot;. 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 &amp;quot; http://en.wikipedia.org/wiki/First-class_object &amp;quot;
  • #137 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
  • #138 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
  • #139 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
  • #140 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
  • #141 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
  • #142 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
  • #143 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
  • #144 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
  • #145 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
  • #146 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
  • #147 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
  • #148 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
  • #149 Source: cv-qualified type : http://www.embedded.com/showArticle.jhtml?articleID=9900322 A cv-qualified type has the form &amp;quot; cv T &amp;quot; 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 &gt;= cv2 , if every cv-qualifier in cv2 also appears in cv1 . If cv1 &gt;= 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
  • #150 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
  • #151 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
  • #152 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
  • #153 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
  • #154 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
  • #155 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
  • #156 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
  • #157 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
  • #158 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 &amp;quot;std::bad_weak_ptr&amp;quot;.” – What does it mean?
  • #159 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
  • #160 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
  • #161 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
  • #162 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
  • #163 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
  • #164 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
  • #172 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