base::SharedPtrNullLocked Class Reference

Variant of SharedPtr that can be NULL. More...


Detailed Description

Variant of SharedPtr that can be NULL.

///
/// ##################################################
/// If NULL pointer is unavoidable, use SharedPtrNull.
/// Regular SharedPtr will malfunction if given NULL.
/// ##################################################
///
/// Interface:
/// ----------
///                 SharedPtr( void );     // default ctor constructs a new T
///                 SharedPtrNull( void);  // -or- default ctor constructs NULL pointer
///                 SharedPtr( T* obj );
///                 SharedPtr( const SharedPtr<T>& src );
///                 ~SharedPtr();
/// SharedPtr<T>&   operator=( const SharedPtr<T>& src );
/// SharedPtr<T>&   operator=( T* obj );
/// T*              operator->( void ) const;
/// T&              operator*( void ) const;
/// bool            operator==( const SharedPtr& other ) const;
/// bool            operator!=( const SharedPtr& other ) const;
/// bool            operator==( const T* obj ) const;
/// bool            operator!=( const T* obj ) const;
/// T*              PTR();
/// T&              REF();
/// const T*        CONST_PTR();
/// const T&        CONST_REF();
///
/// Overview:
/// ---------
/// Shared is a base class that provides storage for a reference-count.
/// Shared itself is a NOP.  Rather, objects to be reference-counted are given
/// to a SharedPtr which maintains the reference-count.
///
/// SharedPtr will own the object and is responsible for deleting the object.
/// Sharing an object is done by copying a SharedPtr which increments
/// the reference-count (in the Shared base part of the object).
/// When a SharedPtr is deleted, ~SharedPtr decrements the reference-count
/// and deletes the object when the count falls to zero.
///
/// Usage:
/// ------
/// Sharing an object is done by copying SharedPtr objects.
/// Copying a SharedPtr increments a reference count of the object being shared.
///
///     SharedPtr<Object> shared1( new Object );
///     SharedPtr<Object> shared2 = shared1;  // copy constructor
///
/// Passing a SharedPtr to a function is implicit copying,
/// so the caller and callee shares the object.
/// A SharedPtr should be passed by value (not as a pointer/reference):
///
///     void Func( SharedPtr<Object> obj );   // right
///     void Func( SharedPtr<Object>& obj );  // wrong, inhibits necessary copying method
///
/// Directly assigning a SharedPtr with a pointer unshares one count of the outgoing object,
/// and resets the SharedPtr's reference count to 1 for the incoming object.
///
///     SharedPtr<Object> ptr1( new Object );
///     SharedPtr<Object> ptr2 = ptr1;      // ptr1 and ptr2 share one Object (refCnt=2)
///     ptr2 = new Object;                  // ptr2 points to different Object (refCnt=1, refCnt=1)
///
/// const SharedPtr example:
///
///     SharedPtr<const Object> objc = new Object;
///     SharedPtr<Object> obj = new Object;
///     objc = obj;  // ok (unless const object is supposed to be undeletable)
///     obj = objc;  // won't compile
///
/// SharedPtr can effectively transfer ownership to caller:
///
///     SharedPtr<Object>
///     Producer( void )
///     {
///         SharedPtr<Object> obj = new Object;
///         obj->AddData(..);
///         ...
///         return obj;
///     }
///
/// A Shared object can be converted to a raw pointer
/// and then converted back to a SharedPtr variable.
/// This is very useful for a Visitor pattern which ordinarily
/// visits nodes in terms of raw pointers for speed, but rarely
/// needs to retain a reference-counted pointer to a node.
///
/// class Node : public Shared { };
///
/// class Visitor
/// {
///     void Visit( Node& node )
///     {
///         if ( node == sought )
///         {
///             // Can be thought of as a conversion from Node* to SharedPtr<Node>.
///             // Actually invokes SharedPtr::operator=(T*) which increases ref cnt.
///             mMatch = &node;
///         }
///     }
///
/// private:
///     SharedPtr<Node>    mMatch;
/// };
///
/// Examples:
/// ---------
/// Instead of copying a 1MB pixmap requiring explicit memory management...
///
///     class Pixmap
///     {
///         uint8* GetBuf();
///     };
///     
///     class Object
///     {
///        Object( Pixmap& pixmap )
///        {
///            mBuf = new uint8[pixmap.GetBufLen()];  // new array
///            memcpy( mBuf, pixmap.GetBuf(), pixmap.GetBufLen() );  // copy array
///        }
///        ~Object()
///        {
///            delete[] mBuf;  // free array
///        }
///        uint8* mBuf;
///     };
///
/// ...using SharedPtr is way faster and simpler/safer as delete is eliminated:
///
///     class Pixmap
///     {
///         SharedPtr< Array<uint8> > GetBuf();  // shared array
///     };
///
///     class Object
///     {
///        Object( Pixmap& pixmap )
///        {
///            mBuf = pixmap.GetBuf();  // SharedPtrArr assignment is fast
///        }
///        ~Object()  // dtor now does nothing
///        {
///        }
///        SharedPtr< Array<uint8> > mBuf;  // shared array
///     };
///
/// An individual Shared object is interchangable between the variants of SharedPtr.
/// --------------------------------------------------------------------------------
/// The Shared object is independent of the SharedPtr that encapsulates it.
/// By using PTR(), a Shared can be extract from one kind of SharedPtr
/// and exchanged with another kind of SharedPtr.
///
/// SharedPtr<Data> data = new Data;
/// Producer producer( data.PTR() );
/// class Producer
/// {
///     Producer( SharedPtrNull<Data> data );  // Shared interchanged as SharedPtrNull
/// };
///
/// SharedPtrNull:
/// --------------
/// Regular SharedPtr must be optimal since it is extremely frequent.
/// If a NULL SharedPtr is possible and unavoidable, use the slower SharedPtrNull.
/// The same Shared object can be interchanged in a SharedPtr or SharedPtrNull
/// (as long as the value isn't NULL at run-time of course).
///
/// SharedPtrNull can point to abstract objects (unlike SharedPtr which
/// requires a default ctor which abstract classes lack).
///
/// An example of an unavoidable case where SharedPtr has to be NULL (interimly):
/// class Font
/// {
///   //SharedPtr<Texture>      mTexture;  // WRONG!  SharedPtr ctor will crash!
///     SharedPtrNull<Texture>  mTexture;  // ok, SharedPtrNull can handle NULL
/// };
/// Font::Font( const FontDesc& desc, SafePtr<Gui> gui )
/// :   mTexture(NULL)
/// {
///     [load .tga file]
///     mTexture = new Texture( targa, Texture::eMipmap_ON );
/// }
///
/// Rules and pitfalls:
/// -------------------
/// - Ways affecting the reference-count:
///
///   - passed as an arg
///   - returned
///   - constructed/destructed as a class member
///   - reassigned with a new object or another SharedPtr (src SharedPtr affected too)
///   - copied directly
///   - copied indirectly (as a member of a copyable class, container element, etc)
///
/// - Be aware that once a Shared object is encapsulated in a SharedPtr,
///   it becomes subject to automatic deletion by SharedPtr.
///
/// - Transferring ownership vs. sharing ownership:
///
///   SharedPtr is usually for sharing ownership, but it can be used to transfer ownership.
///
///   class Object : public Shared
///   {
///       // share ownership:
///       SharedPtr<Buffer>  GetBuffer( void ) { return mBuffer; }
///       SharedPtr<Buffer>  mBuffer;
///
///       // transfer ownership:
///       SharedPtr<Buffer>  GetBuffer( void ) { return new Buffer; }
///
///       // WRONG/BUG (see below):
///       SharedPtr<Buffer>  GetBuffer( void ) { return mBuffer; }
///       Buffer*            mBuffer;
///   };
///
/// - PITFALL: A Shared, as a class member, must be encapsulated in SharedPtr:
///
///   Otherwise, as an actual member or a raw pointer, a Shared object
///   will initially have a zero reference-count.  But the the class instance
///   implicitly references it.  Any accessor method in the class that
///   returns it as a SharedPtr can may prematurely destroy it.
///   Though not recommended, if a Shared needs to be an actual member,
///   the class ctor can use Shared::IncRefCnt() to account for its reference.
///
///   class Node : public Shared
///   {
///   };
///   class Graph
///   {
///       SharedPtr<Node>  GetRoot( void ) { return mRoot; }
///
///       Node*            mRoot;  // WRONG
///       Node             mRoot;  // WRONG
///       SharedPtr<Node>  mRoot;  // ok
///   };
///
/// - Don't blindly change T* to SharedPtr<T>:
///
///   Buffer sBuffer;
///   < Buffer* GetBuffer( void )            // original code
///   > SharedPtr<Buffer> GetBuffer( void )  // revised code
///   {
///       return sBuffer;  // oops: implicitly converted to SharedPtr and deleted!
///   }
///
/// - Pitfalls in replacing raw pointers with SharedPtr:
///
/// < Object* mObject;
/// > SharedPtr<Object> mObject;
///   delete mObject; mObject = new Object;  // renew idiom
///
///   SharedPtr::operator=() will malfunction by try freeing the deleted mObject.
///   Correction is to reassign SharedPtr without deleting.
///
///   SharedPtr<Object> mObject;
///   mObject = new Object;  // reassign SharedPtr
///
/// Design notes:
/// -------------
/// Disadvantages are that SharedPtr intrusively requires deriving from Shared
/// and wastes an int in objects that aren't actually shared.
/// But the advantage is speed: the reference-count is allocated along with
/// the object, as opposed to having a separately allocated reference-count.
/// This advantage becomes important when lots of small objects are shared
/// and frequently created.
///
/// 

The documentation for this class was generated from the following file: Palomino 3D Engine documents generated by doxygen 1.5.3 on Fri Nov 23 11:26:20 2007