# Presentation: 009398

## Teuchos::RefCountPtrAn Introduction to the Trilinos Smart Reference-Counted Pointer Class for (Almost) Automatic Dynamic Memory Management in C++ 

**Roscoe A. Bartlett**
** **
**Department (1411) 9211: Optimization and Uncertainty Estimation**
**Sandia National Laboratories**

- Sandia is a multiprogram laboratory operated by Sandia Corporation, a Lockheed Martin Company,for the United States Department of Energy under contract DE-AC04-94AL85000.

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- Summary and RefCountPtr philosophy

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- Summary and RefCountPtr philosophy

## Dynamic Memory Management in C++

- C++ requires programmers to manage dynamically allocated memory themselves using operator new and operator delete
- Problems with using raw new and delete at application programming level
- Very error prone (multiple deletes or memory leaks)
- Difficult to know who’s responsibility it is to delete an object
- Creates memory leaks when exceptions are thrown
- Reference counting to the rescue?

- _Client A_

- _Client B_

- _Client C_

- _Reference Count Node_

- count=3

- _Shared Object_

- How is the reference count updated and managed?
- When is the object deleted?
- How is the object deleted?

- Examples (C++ and other):
- CORBA
- COM

- UML object diagram

## Smart Pointers : A C++ Reference Counting Solution

- C++ supports development of “smart” pointer classes that behave a lot like raw pointers
- Reference counting + smart pointers = smart reference counted pointers

- _Smart Ptr A_

- _Smart Ptr B_

- _Smart Ptr C_

- _Reference Count Node_

- count=3

- _Shared Object_

- Examples of C++ smart reference counted pointer classes
- boost::shared_ptr:  Part of the Boost C++ class library (created in 1999?)
- Being considered to go into the next C++ standard
- Does not throw exceptions
- Teuchos::RefCountPtr:
- Originally developed as part of rSQP++ (Bartlett et. al.) in 1998
- Does throw exceptions in some cases in debug mode and has addition features
- Being used more and more extensively in Thyra, NOX/LOCA, Rythmos, Belos, Anasazi, TSFExtended, Charon, ...

- _Client A_

- _Client B_

- _Client C_

- Advantages of Smart Pointer approach:
- Access to shared object uses pointer-like syntax
- (*ptr).f()   [operator*()]
- ptr->f()    [operator->()]
- Reference counts automatically updated and maintained
- Object automatically deleted when last smart pointer is destroyed

## RefCountPtr SAND Reports

-   _[http://software.sandia.gov/Trilinos/RefCountPtrBeginnersGuideSAND.pdf](http://software.sandia.gov/Trilinos/RefCountPtrBeginnersGuideSAND.pdf)_
-   Trilinos/doc/RefCountPtr/RefCountPtrSAND.tex (to be completed)

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- Summary and RefCountPtr philosophy

## Introduction of Simple Example Program

- Example program that is described in the Beginner’s Guide
- Complete program listings in Appendix E and F
- Uses basic object-oriented programming
- Demonstrates the basic problems of using raw C++ pointers and delete for high-level memory management
- Provides context for differentiating “persisting” and “non-persisting” object associations
- Show step-by-step process of refactoring C++ code to use RefCountPtr

## Abstract Interfaces and Subclasses in Example Program

- class UtilityBase {
- public:
-   virtual void f() const = 0;
- };

- Utility interface and subclasses

- class UtilityBaseFactory {
- public:
-   virtual UtilityBase* createUtility() const = 0;
- };

- Utility “abstract factory” interface and subclasses (see “Design Patterns” book)

- class UtilityA : public UtilityBase {
- public:
-   void f() const {...}
- };
- class UtilityB : public UtilityBase {
- public:
-   void f() const {...}
- };

- class UtilityAFactory : public UtilityBaseFactory {
- public:
-   UtilityBase* createUtility() const { return new UtilityA(); }
- };
- class UtilityBFactory : public UtilityBaseFactory {
- public:
-   UtilityBase* createUtility() const { return new UtilityB(); }
- };

## Client Classes in Example Program

- class ClientA {
- public:
-   void f( const UtilityBase &utility ) const { utility.f(); }
- };

- class ClientB {
-   UtilityBase *utility_;
- public:
-   ClientB() : utility_(0) {}
-   ~ClientB() { delete utility_; }
-   void initialize( UtilityBase *utility ) { utility_ = utility; }
-   void g( const ClientA &a ) { a.f(*utility_); }
- };

- class ClientC {
-   const UtilityBaseFactory *utilityFactory_;
-   UtilityBase              *utility_;
-   bool                     shareUtility_;
- public:
-   ClientC( const UtilityBaseFactory *utilityFactory, bool shareUtility )
-     :utilityFactory_(utilityFactory)
-     ,utility_(utilityFactory->createUtility())
-     ,shareUtility_(shareUtility) {}
-   ~ClientC() { delete utilityFactory_; delete utility_; }
-   void h( ClientB *b ) {
-     if( shareUtility_ ) b->initialize(utility_);
-     else                b->initialize(utilityFactory_->createUtility());
-   }
- };

## Example Main Program

- int main( int argc, char* argv[] )
- {
-   // Read options from the commandline
-   bool useA, shareUtility;
-   example_get_args(argc,argv,&useA,&shareUtility);
-   // Create factory
-   UtilityBaseFactory *utilityFactory = 0;
-   if(useA) utilityFactory = new UtilityAFactory();
-   else     utilityFactory = new UtilityBFactory();
-   // Create clients
-   ClientA a;
-   ClientB b1, b2;
-   ClientC c(utilityFactory,shareUtility);
-   // Do some stuff
-   c.h(&b1);
-   c.h(&b2);
-   b1.g(a);
-   b2.g(a);
-   // Cleanup memory
-   delete utilityFactory;
- }

- This program has memory usage problems!

## Example Program Memory Usage Problem #1

**Example Program Memory Usage Problem #1**

- int main( int argc, char* argv[] )
- {
-   ...
-   // Create factory
-   UtilityBaseFactory *utilityFactory = 0;
-   if(useA) utilityFactory = new UtilityAFactory();
-   else     utilityFactory = new UtilityBFactory();
-   // Create clients
-   ...
-   ClientC c(utilityFactory,shareUtility);
-   // Do some stuff
-   ...
-   // Cleanup memory
-   delete utilityFactory;
- }

- class ClientC {
-   ...
- public:
-   ClientC( const UtilityBaseFactory *utilityFactory, bool shareUtility )
-     :utilityFactory_(utilityFactory)
-     ,utility_(utilityFactory->createUtility())
-     ,shareUtility_(shareUtility) {}
-   ~ClientC() { delete utilityFactory_; delete utility_; }
-   ...
- };

- The UtilityBaseFactory object is deleted twice!

## Example Program Memory Usage Problem #2

**Example Program Memory Usage Problem #2**

- class ClientB {
-   UtilityBase *utility_;
- public:
-   ~ClientB() { delete utility_; }
-   void initialize( UtilityBase *utility ) { utility_ = utility; }
- };

- class ClientC {
-   const UtilityBaseFactory *utilityFactory_;
-   UtilityBase              *utility_;
-   bool                     shareUtility_;
- public:
-   ...
-   ~ClientC() { delete utilityFactory_; delete utility_; }
-   void h( ClientB *b ) {
-     if( shareUtility_ ) b->initialize(utility_);
-     else                b->initialize(utilityFactory_->createUtility());
-   }
- };

- int main( int argc, char* argv[] )
- {
-   ...
-   ClientB b1, b2;
-   ClientC c(utilityFactory,shareUtility);
-   c.h(&b1);
-   c.h(&b2);
-   ...
- }

- The UtilityBase object is deleted three times if shareUtility_==true!

## Problems with using raw pointers for memory management

**Important points**
- Fixing the memory management problems in this example program is not too hard
- However, writing complex OO software with independently developed modules without memory leaks nor multiple calls to delete is very hard!
- Example: Epetra required major refactoring to address these problems!
- The designers of C++ never expected complex high level code to rely on raw C++ memory management and raw calls to delete
- Almost every major C++ middleware software collection provides some higher-level support for dynamic memory management and wraps raw calls to delete
- Raw calls to delete are fragile and create memory leaks in the presents of exceptions

- void someFunction() {
-   A *a = new A;
-   a->f();  // memory leak on throw!
-   delete a;
- }

- What is an alternative to using raw pointers for memory management?
- Smart Reference Counted Pointers!  => Teuchos::RefCountPtr

- void someFunction() {
-   std::auto_ptr<A> a(new A);
-   a->f();  // no leak on throw!
- }

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- Summary and RefCountPtr philosophy

## RefCountPtr: Persisting and Non-Persisting Associations

**RefCountPtr: Persisting and Non-Persisting Associations**

- class ClientB {
-   UtilityBase *utility_;
- public:
-   ClientB() : utility_(0) {}
-   ~ClientB() { delete utility_; }
-   void initialize( UtilityBase *utility ) { utility_ = utility; }
-   void g( const ClientA &a ) { a.f(*utility_); }
- };

- ClientB

- ClientA

- UtilityBase

- class ClientA {
- public:
-   void f( const UtilityBase &utility ) const { utility.f(); }
- };

- Non-persisting associations:
- Use raw C++ references and pointers
- Persisting associations:
- Use RefCountPtr

- Non-persisting association:  An object association that only exists within a single function call and no “memory” of the object persists after the function exits
- Persisting association:  An object association that exists beyond a single function call and where some “memory” of the object persists
- Examples:

- UML class diagram

- Non-persisting association

- Persisting association

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- Summary and RefCountPtr philosophy

## Refactoring Example Program to use RefCountPtr : Part #1

- class UtilityBaseFactory {
- public:
-   virtual UtilityBase* createUtility() const = 0;
- };

- Before Refactoring

- After Refactoring

- class UtilityBaseFactory {
- public:
-   virtual **RefCountPtr<UtilityBase>** createUtility() const = 0;
- };

- class UtilityAFactory : public UtilityBaseFactory {
- public:
-   UtilityBase* createUtility() const { return new UtilityA(); }
- };
- class UtilityBFactory : public UtilityBaseFactory {
- public:
-   UtilityBase* createUtility() const { return new UtilityB(); }
- };

- class UtilityAFactory : public UtilityBaseFactory {
- public:
-   **RefCountPtr<UtilityBase>** createUtility() const { return **rcp(**new UtilityA()**)**; }
- };
- class UtilityBFactory : public UtilityBaseFactory {
- public:
-   **RefCountPtr<UtilityBase>** createUtility() const { return **rcp(**new UtilityB()**)**; }
- };

## Refactoring Example Program to use RefCountPtr : Part #2

**Refactoring Example Program to use RefCountPtr : Part #2**

- Before Refactoring

- After Refactoring

- class ClientA {
- public:
-   void f( const UtilityBase &utility ) const { utility.f(); }
- };

- class ClientB {
-   UtilityBase *utility_;
- public:
-   ClientB() : utility_(0) {}
-   ~ClientB() { delete utility_; }
-   void initialize( UtilityBase *utility ) { utility_ = utility; }
-   void g( const ClientA &a ) { a.f(*utility_); }
- };

- class ClientA {
- public:
-   void f( const UtilityBase &utility ) const { utility.f(); }
- };

- class ClientB {
-   **RefCountPtr<UtilityBase> utility_**;
- public:
-   void initialize(**const RefCountPtr<UtilityBase> &**utility) { utility_=utility; }
-   void g( const ClientA &a ) { a.f(*utility_); }
- };

- Constructor and Destructor are Gone!

- After Refactoring (no change)

- Before Refactoring

## Refactoring Example Program to use RefCountPtr : Part #3

**Refactoring Example Program to use RefCountPtr : Part #3**

- Before Refactoring

- After Refactoring

- class ClientC {
-   const UtilityBaseFactory *utilityFactory_;
-   UtilityBase              *utility_;
-   bool                     shareUtility_;
- public:
-   ClientC( const UtilityBaseFactory *utilityFactory, bool shareUtility )
-     :utilityFactory_(utilityFactory)
-     ,utility_(utilityFactory->createUtility())
-     ,shareUtility_(shareUtility) {}
-   ~ClientC() { delete utilityFactory_; delete utility_; }
-   void h( ClientB *b ) {
-     if( shareUtility_ ) b->initialize(utility_);
-     else                b->initialize(utilityFactory_->createUtility());
-   }
- };

- class ClientC {
-   **RefCountPtr<const UtilityBaseFactory>** utilityFactory_;
-   **RefCountPtr<UtilityBase>**              utility_;
-   bool                                  shareUtility_;
- public:
-   ClientC(**const RefCountPtr<const UtilityBaseFactory> &**utilityFactory, ... )
-     :utilityFactory_(utilityFactory)
-     ,utility_(utilityFactory->createUtility())
-     ,shareUtility_(shareUtility) {}
-   void h( ClientB *b ) {...}
- };

- Destructor is Gone!

## Refactoring Example Program to use RefCountPtr : Part #4

**Refactoring Example Program to use RefCountPtr : Part #4**

- int main( int argc, char* argv[] )
- {
-   // Read options from the commandline
-   bool useA, shareUtility;
-   example_get_args(argc,argv,&useA
-                    ,&shareUtility);
-   // Create factory
-   UtilityBaseFactory *utilityFactory = 0;
-   if(useA)
-     utilityFactory=new UtilityAFactory();
-   else
-     utilityFactory=new UtilityBFactory();
-   // Create clients
-   ClientA a;
-   ClientB b1, b2;
-   ClientC c(utilityFactory,shareUtility);
-   // Do some stuff
-   c.h(&b1);
-   c.h(&b2);
-   b1.g(a);
-   b2.g(a);
-   // Cleanup memory
-   delete utilityFactory;
- }

- Before Refactoring

- After Refactoring

- int main( int argc, char* argv[] )
- {
-   // Read options from the commandline
-   bool useA, shareUtility;
-   example_get_args(argc,argv,&useA
-                    ,&shareUtility);
-   // Create factory
-   **RefCountPtr<UtilityBaseFactory>** utilityFactory;
-   if(useA)
-     utilityFactory = **rcp(**new UtilityAFactory()**)**;
-   else
-     utilityFactory = **rcp(**new UtilityBFactory()**)**;
-   // Create clients
-   ClientA a;
-   ClientB b1, b2;
-   ClientC c(utilityFactory,shareUtility);
-   // Do some stuff
-   c.h(&b1);
-   c.h(&b2);
-   b1.g(a);
-   b2.g(a);
- }

- New program runs without any memory problems
- New program will be easier to maintain

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- More background
- Construction, reinitialization, and object access
- Explicit casting
- Recommendations for passing objects to and from functions
- Implicit casting
- Common casting problems
- Summary and RefCountPtr philosophy

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- More background
- Construction, reinitialization, and object access
- Explicit casting
- Recommendations for passing objects to and from functions
- Implicit casting
- Common casting problems
- Summary and RefCountPtr philosophy

## Value Semantics vs. Reference Semantics

- A. Value Semantics

- class S {
- public:
-   S();                    // Default constructor
-   S(const S&);            // Copy constructor
-   S& operator=(const S&); // Assignment operator
-   ...
- };

- Used for small, concrete datatypes
- Identity determined by the value in the object, not by its object address (e.g. obj==1.0)
- Storable in standard containers (e.g. std::vector<S>)
- Examples: int, bool, float, double, char, std::complex, extended precision ...

- B. Reference Semantics

- class A {
- public:
-   // Pure virtual functions
-   virtual void f() = 0;
-   ...
- };

- Abstract C++ classes (i.e. has pure virtual functions) or for large objects
- Identity determined by the object’s address (e.g. &obj1 == &obj2)
- Can not be default constructed, copied or assigned (not storable in standard containers)
- Examples: std::ostream, any abstract base class, ...

- Important points!
- RefCountPtr class has
-    value semantics
- RefCountPtr usually wraps classes with reference semantics

## Raw Pointers and RefCountPtr : const and non-const

- _Raw C++ Pointers_

- _RefCountPtr_

- typedef A*       ptr_A;

- RefCountPtr<A>

- typedef const A* ptr_const_A;

- RefCountPtr<const A>

- equivalent to

- equivalent to

- non-const pointer to non-const object

- ptr_A               a_ptr;

- A *                 a_ptr;

- RefCountPtr<A>             a_ptr;

- equivalent to

- const pointer to non-const object

- const ptr_A         a_ptr;

- A * const           a_ptr;

- const RefCountPtr<A>       a_ptr;

- equivalent to

- non-const pointer to const object

- ptr_const_A         a_ptr;

- const A *           a_ptr;

- RefCountPtr<const A>       a_ptr;

- equivalent to

- const pointer to const object

- const ptr_const_A   a_ptr;

- const A * const     a_ptr;

- const RefCountPtr<const A> a_ptr;

- equivalent to

- an address

- A’s data

- a_ptr

- Important Point:  A pointer object a_ptr of type A* is an object just like any other object with value semantics and can be const or non-const

- A  a;
- A* a_ptr = &a;

- a

- Example:

- Remember this equivalence

- an address

- A’s data

- an address

- A’s data

- an address

- A’s data

- an address

- A’s data

## Example C++ Class Hierarchies

- // Abstract hierarchy
- class A {
- public:
-   virtual ~A(){}
-   virtual void f(){...}
- };
- class B1 : virtual public A {...};
- class B2 : virtual public A {...};
- class C : virtual public B1, virtual public B2 {...};

- Assume all these classes have reference semantics

- // Non-abstract hierarchy (no virtual functions)
- class D {...};
- class E : public D {...};

- UML class diagram

- A

- B1

- B2

- C

- D

- E

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- More background
- Construction, reinitialization, and object access
- Explicit casting
- Recommendations for passing objects to and from functions
- Implicit casting
- Common casting problems
- Summary and RefCountPtr philosophy

## Constructing RefCountPtr Objects

- template<class T>
- class RefCountPtr {
- public:
-   RefCountPtr( ENull null_arg = null );
-   ...
- };
- template<class T> RefCountPtr<T> rcp( T* p );
- template<class T> RefCountPtr<T> rcp( T* p, bool owns_mem);

- C++ Declarations for constructing a RefCountPtr object

- RefCountPtr<C> c_ptr;          // Good for class data members!
- RefCountPtr<C> c_ptr = null;   // May help clarity

- void foo( const UtilityBase &utility )  // Non-persisting with utility
- {
-   ClientB b;
-   b.initialize(rcp(&utility,false));    // b lives entirely in foo()
-   ...
- }

- Initializing a RefCountPtr<> object to NULL

- Creating a RefCountPtr object using new

- RefCountPtr<C> c_ptr = rcp(new C);

- C              c;
- RefCountPtr<C> c_ptr = rcp(&c,false);

- Initializing a RefCountPtr object to an object not allocated with new

- Example

## Commandment 1 : Give a ‘new’ object to just one RCP

**Commandment 1:**  *Thou shall put a pointer for an object allocated with operator **new** into a **RefCountPtr** object only once.  E.g.  *

**Anti-Commandment 1:**  *Thou shall never give a raw C++ pointer returned from operator **new** to more than one **RefCountPtr** object.*

- Example:
-   A *ra_ptr = new C;
-   RefCountPtr<A> a_ptr1 = rcp(ra_ptr); // Okay
-   RefCountPtr<A> a_ptr2 = rcp(ra_ptr); // no, No, NO !!!!

- a_ptr2 knows nothing of a_ptr1 and both will call delete!

**Anti-Commandment 2:**  *Thou shall never give a raw C++ pointer to an array of objects returned from operator **new[]** to a **RefCountPtr** object using **rcp(new C[n])**.*

- Example:
-   RefCountPtr<std::vector<C> >
-     c_array_ptr1 = rcp(new std::vector<C>(N)); // Okay
-   RefCountPtr<C>
-     c_array_ptr2 = rcp(new C[n]);              // no, No, NO!

- c_array_ptr2 will call delete instead of delete []!

- RefCountPtr<C> c_ptr = rcp(new C);

## Reinitialization of RefCountPtr Objects

- template<class T>
- class RefCountPtr {
- public:
-   RefCountPtr<T>& operator=(const RefCountPtr<T>& r_ptr);
-   ...
- };

- C++ Declarations for reinitializing a RefCountPtr Object

- RefCountPtr<A> a_ptr;
- a_ptr = rcp(new A());

- Resetting from a raw pointer

- RefCountPtr<A> a_ptr = rcp(new A());
- a_ptr = null; // The A object will be deleted here

- Resetting to null

- RefCountPtr<A> a_ptr1;
- RefCountPtr<A> a_ptr2 = rcp(new A());
- a_ptr1 = a_ptr2; // Now a_ptr1 and a_ptr2 point to the same A object

- Assigning from a RefCountPtr object

- The proper way to reinitialize an object with value semantics is to use the assignment operator! (boost::shared_ptr violates this principle!)

## Access Underlying Reference-Counted Object

- template<class T>
- class RefCountPtr {
- public:
-   T* operator->() const;   // Allows ptr->f();  [throws exception if NULL]
-   T& operator*() const;    // Allows (*ptr).f() [throws exception if NULL]
-   T* get() const;
-   ...
- };
- template<class T> bool is_null(const RefCountPtr<T>& p);
- template<class T> bool operator==(const RefCountPtr<T>& p, ENull);
- template<class T> bool operator!=(const RefCountPtr<T>& p, ENull);

- C++ Declarations for accessing referenced-counted object

- C &c_ref = *c_ptr; // Throws exception if c_ptr.get()==NULL

- Access to object reference (debug runtime checked)

- C *c_rptr = c_ptr.get(); // Never throws an exception

- Access to object pointer (unchecked, may return NULL)

- C *c_rptr = &*c_ptr; // Throws exception if c_ptr.get()==NULL

- Access to object pointer (debug runtime checked, will not return NULL)

- c_ptr->f(); // Throws exception if c_ptr.get()==NULL

- Access of object’s member (debug runtime checked)

- if( a_ptr.get()==NULL ) std::cout << “a_ptr is null\n”;
- if( is_null(a_ptr)    ) std::cout << “a_ptr is null\n”;
- if( a_ptr==null       ) std::cout << “a_ptr is null\n”;

- Testing for null

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- More background
- Construction, reinitialization, and object access
- Explicit casting
- Recommendations for passing objects to and from functions
- Implicit casting
- Common casting problems
- Summary and RefCountPtr philosophy

## Explicit Casting of RefCountPtr Objects : Template Functions

- // implicit cast
- template<class T2, class T1>
- RefCountPtr<T2> rcp_implicit_cast(const RefCountPtr<T1>& p1);
- // static cast
- template<class T2, class T1>
- RefCountPtr<T2> rcp_static_cast(const RefCountPtr<T1>& p1);
- // const cast
- template<class T2, class T1>
- RefCountPtr<T2> rcp_const_cast(const RefCountPtr<T1>& p1);
- // dynamic cast
- template<class T2, class T1>
- RefCountPtr<T2> rcp_dynamic_cast(const RefCountPtr<T1>& p1
-                                  ,bool throw_on_fail = false );

- C++ Declarations for explicit casting of RefCountPtr Objects

## Explicit Casting of RefCountPtr Objects : Examples

- _Raw C++ Pointers_

- _RefCountPtr_

- D*
-   d = new E;
- E*
-   e = static_cast<E*>(d);

- RefCountPtr<D>
-   d  = rcp(new E);
- RefCountPtr<E>
-   e = rcp_static_cast<E>(d);

- Static cast (non-checked)

- Constant cast

- const A*
-   ca = new C
- A*
-   a = const_cast<A*>(ca);

- RefCountPtr<const A>
-   ca = rcp(new C);
- RefCountPtr<A>
-   a = rcp_const_cast<A>(ca);

- Dynamic cast (runtime check, can return NULL on fail)

- A*
-   a = new C;
- B1*
-   b1 = dynamic_cast<B1*>(a);

- RefCountPtr<A>
-   a = rcp(new C);
- RefCountPtr<B1>
-   b1 = rcp_dynamic_cast<B1>(a);

- A*
-   a = new B1;
- B2*
-   b2 = ( a ? &dynamic_cast<B2&>(*a)
-            : (B2*)NULL              );

- RefCountPtr<A>
-   a = rcp(new B1);
- RefCountPtr<B2>
-   b2 = rcp_dynamic_cast<B2>(a,true);

- A

- B1

- B2

- C

- D

- E

- Note: In last dynamic cast, rcp_dynamic_cast<B2>(a,true) throws exception with much better error message than dynamic_cast<B2&>(*a).   See Teuchos::dyn_cast<>()!

- Dynamic cast (runtime check, can not return NULL on fail)

## Commandment 4 : Casting RefCountPtr Objects

**Commandment 4:**  *Thou shall only cast between **RefCountPtr** objects using the default copy constructor (for implicit conversions) and the nonmember template functions **rcp_implicit_cast<>(...)**, **rcp_static_cast<>(...)**, **rcp_const_cast<>(...)**  and **rcp_dynamic_cast<>(...)**.*

**Anti-Commandment 5:**  *Thou shall never convert between **RefCountPtr** objects using raw pointer access.*

- Example:
- RefCountPtr<A>     a_ptr   = rcp(new C);
- RefCountPtr<B1>    b1_ptr1 = rcp_dynamic_cast<B1>(a_ptr);         // Yes :-)
- RefCountPtr<B1>    b1_ptr2 = rcp(dynamic_cast<B1*>(a_ptr.get())); // no, No, NO !!!

- b1_ptr2 knows nothing of a_ptr and both will call delete!

- A

- B1

- B2

- C

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- More background
- Construction, reinitialization, and object access
- Explicit casting
- Recommendations for passing objects to and from functions
- Implicit casting
- Common casting problems
- Summary and RefCountPtr philosophy

## Recommendations for passing objects to and from C++ functions

- non-changeable
- [input]

- persisting
- non-changeable

- non-persisting
- changeable
- [input-output]

- persisting
- changeable

- )

- (

- out = func( args )

**Recommendations for passing objects to and from C++ functions**

- A*
- A&
- const A*
- const A&

- RCP<A>
- RCP<const A>
- const RCP<A>&
- const RCP<const A>&

- A*
- A&

- RCP<A>
- const RCP<A>&

- Recommendations for writing function prototypes for passing objects that:
- Lead to code that is as self documenting as possible (write less extra documentation)
- Maximizes compile-time checking
- Maximizes runtime performance and simplifies debugging

- out = func

- Consider passing objects of type A which use reference semantics

- optional
- required

- Passing RefCountPtr objects by constant reference :
- Avoids needless copy constructor and destructor calls
- Makes it easier to step into function in a debugger
- Avoids accidentally resetting RefCountPtr

- A*
- A&
- const A*
- const A&
- RCP<A>
- RCP<const A>

- See Appendix D in Beginner’s Guide for more recommendations
- objects with value semantics, arrays, arrays of RefCountPtr objects etc.

- Recommended

- Return RefCountPtr objects by value

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- More background
- Construction, reinitialization, and object access
- Explicit casting
- Recommendations for passing objects to and from functions
- Implicit casting
- Common casting problems
- Summary and RefCountPtr philosophy

## Implicit Casting in Function Calls : Raw C++ Pointers

- // Typedefs
- typedef A*        ptr_A;
- typedef const A*  ptr_const_A;
- // Takes pointer to A (by value)
- void foo1( ptr_A a_ptr );
- // Takes pointer to const A (by value)
- void foo2( ptr_const_A a_ptr );
- // Takes pointer to A (by const reference)
- void foo3( const ptr_A &a_ptr );
- // Takes pointer to A (by non-const reference)
- void foo4( ptr_A &a_ptr );
- void boo1()
- {
-   C* c = new C;
-   A* a = c;
-   foo1(c); // Okay, implicit cast to base class
-   foo2(a); // Okay, implicit cast to const
-   foo2(c); // Okay, implicit cast to base class and const
-   foo3(c); // Okay, implicit cast to base class
-   foo4(a); // Okay, no cast
-   foo4(c); // Error, can not cast from (C&*) to (A&*)!
- }

- A

- B1

- B2

- C

- Compiler can perform implicit conversions on arguments passed by value or const reference!

- Compiler can _not_ perform implicit conversions on arguments passed by non-const reference!

## Implicit Casting of RefCountPtr Objects

- template<class T>
- class RefCountPtr {
- public:
-   template<class T2>
-   RefCountPtr(const RefCountPtr<T2>& r_ptr); // Templated copy constructor!
-   ...
- };
- template<class T2, class T1>
- RefCountPtr<T2> rcp_implicit_cast(const RefCountPtr<T1>& p1);

- C++ Declarations for implicit casting

- A

- B1

- B2

- C

- _Raw C++ Pointers_

- _RefCountPtr_

- C*  c_rptr = new C;
- A*  a_rptr = c_rptr;

- RefCountPtr<C> c_ptr = rcp(new C);
- RefCountPtr<A> a_ptr = c_ptr;

- Implicit cast to base class

- A*        a_rptr  = new A;
- const A*  ca_rptr = a_rptr;

- RefCountPtr<A>       a_ptr  = rcp(new A);
- RefCountPtr<const A> ca_ptr = a_ptr;

- Implicit cast to const

- C*        c_rptr  = new C;
- const A*  ca_rptr = c_rptr;

- RefCountPtr<C>       c_ptr  = rcp(new C);
- RefCountPtr<const A> ca_ptr = c_ptr;

- Implicit cast to base class and const

- Note: Templated copy constructor allows implicit conversion of RefCountPtr objects in almost every situation where an implicit conversion with raw C++ pointers would be allowed

## Implicit Casting : Raw C++ Pointers verses RefCountPtr

- typedef A*       ptr_A;
- typedef const A* ptr_const_A;
- void foo5(ptr_A a_ptr);
- void foo6(ptr_const_A a_ptr);
- void boo2()
- {
-   C* c = new C;
-   A* a = c;
-   foo5(c); // Okay, cast to base
-   foo6(a); // Okay, cast to const
-   foo6(c); // Okay, to base+const
- }

- void foo5(const RefCountPtr<A> &a_ptr);
- void foo6(const RefCountPtr<const A> &a_ptr);
- void boo3()
- {
-   RefCountPtr<C> c = rcp(new C);
-   RefCountPtr<A> a = c;
-   foo5(c); // Okay, cast to base
-   foo6(a); // Okay, cast to const
-   foo6(c); // Okay, to base+const
- }

- _Raw C++ Pointers_

- _RefCountPtr_

- Implicit conversions for RefCountPtr objects to satisfy function calls work almost identically to implicit conversions for raw C++ pointers and raw C++ references except for a few unusual cases:
- Implicit conversions to call overloading functions (see example on next page)
- ???

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- More background
- Construction, reinitialization, and object access
- Explicit casting
- Recommendations for passing objects to and from functions
- Implicit casting
- Common casting problems
- Summary and RefCountPtr philosophy

## Implicit Casting with RefCountPtr : Common Problems/Mistakes

- Passing RefCountPtr by non-const reference instead of by const reference

- Failure to perform implicit conversion with overloaded functions

- void foo7(RefCountPtr<A> &a);
- void foo7(const RefCountPtr<A> &a);
- void boo4() {
-   RefCountPtr<C> c = rcp(new C);
-   RefCountPtr<A> a = c;
-   foo7(a); // Okay, no cast
-   foo7(c); // Error, can not cast involving non-const reference
-   foo7(c); // Okay, implicit case involving const reference okay
- }

-  Programming mistake!

- RefCountPtr<A>       foo9(const RefCountPtr<A>       &a);
- RefCountPtr<const A> foo9(const RefCountPtr<const A> &a);
- RefCountPtr<A> boo5() {
-   RefCountPtr<C> c = rcp(new C);
-   return foo9(c);         // Error, call is ambiguous!
-   RefCountPtr<A> a = c;
-   return foo9(a);         // Okay, calls first foo9(...)
-   return foo9(rcp_implicit_cast<A>(a)); // Okay, calls first foo9(...)
- }

- A

- B1

- B2

- C

- A deficiency of smart pointers over raw pointers

- Calls foo9(A* a) when using raw C++ pointers!

## Outline

- Background on memory management in C++
- Simple motivating example using raw pointers
- Persisting and non-persisting associations
- Refactoring of simple example to use RefCountPtr
- RefCountPtr: Nuts & bolts and avoiding trouble
- Summary and RefCountPtr philosophy

## Summary of RefCountPtr and Advanced Features Overview

- RefCountPtr combines concepts of “smart  pointers” and “reference counting” to build an imperfect but effective “garbage collection” mechanism in C++
- Smart pointers mimic raw C++ pointer usage and syntax
- Value semantics: i.e. default construct, copy construct, assignment etc.
- Object dereference:  i.e. (*ptr).f()
- Pointer member access: i.e. ptr->f()
- Conversions :
- Implicit conversions using templated copy constructor: i.e. C* to A*, and A* to const A*
- Explicit conversions:  i.e. rcp_const_cast<T>(p), rcp_static_cast<T>(p), rcp_dynamic_cast<T>(p)
- Reference counting
- Automatically deletes wrapped object when last reference (i.e. smart pointer) is deleted
- Watch out for circular references!  These create memory leaks!
- RefCountPtr<T> is not a raw C++ pointer!
- Implicit conversions from T* to RefCountPtr<T> and visa versa are not supported!
- Failure of implicit casting and overload function resolution!
- Other problems ...
- Advanced Features (not covered here)
- Template deallocation policy object
- Allows other an delete to be called to clean up
- Allows one smart pointer (i.e. boost::shared_ptr) to be embedded in a RefCountPtr
- Extra data
- Allows RefCountPtr to wrap classes that do not have good memory management (e.g. old Epetra)
- Allows arbitrary events to be registered to occur before or after the wrapped object is deleted

- A

- B1

- B2

- C

## The Philosophy of RefCountPtr

- Using RefCountPtr for only persisting associations increases the vocabulary of the C++ language and makes in more self documenting.
-    void foo( const A &a, const RefCountPtr<C> &c );
- Responsibilities of code that generates shared objects (e.g. factories)
- Create and initialize the concrete object to be given away
- Define the deallocation policy that will be used to deallocate the object
-     RefCountPtr<BaseClass>
-     SomeFactory::create() const {
-       ConcreteSubclass  *instance; InitializeObject(&instance); // Initialize!
-       new rcp(instance,DeallocConcreteSubclass(),true); // Define destruc. policy!
-     }
- Responsibilities of client code maintains persisting associations with shared objects
- Accept RefCountPtr objects that wrap shared objects
- Maintain RefCountPtr objects to shared objects while in use
- Destroy or assign to null RefCountPtr objects when it is finished using shared object
-  class SomeClient {
-    RefCountPtr<A> a_;                                // Maintain A
-  public:
-    void accept(const RefCountPtr<A> &a)  { a_ = a; } // Accept A
-    void clear_out() { a_ = null; }                   // Forget A
-  };
- RefCountPtr allows radically different types of software to be glued together to build a correct and robust memory management system
- Use RefCountPtr to wrap objects not currently wrapped with RefCountPtr and use customized deallocation policies
- Combine different smart pointer objects together

## A Truism

- Ben Parker once said to Peter Parker:

- “With great power comes great responsibility”

- and the same can be said of the use of RefCountPtr and of C++ in general

## Design of RefCountPtr