Skip to content

Instantly share code, notes, and snippets.

@jrandom
Created April 22, 2015 00:44
Show Gist options
  • Save jrandom/ed73f42ca36326c4ca28 to your computer and use it in GitHub Desktop.
Save jrandom/ed73f42ca36326c4ca28 to your computer and use it in GitHub Desktop.
C++11 intrinsic refcounter / smartpointer example code
//
// SmartObject.h
//
#ifndef Tools_Core_SmartObject_h
#define Tools_Core_SmartObject_h
// ================================================================================ Standard Includes
// Standard Includes
// --------------------------------------------------------------------------------
#include <atomic>
#include <mutex>
namespace Core
{
// ============================================================================ SmartObject
// SmartObject
//
// A reference-countable base class
// ----------------------------------------------------------------------------
class SmartObject
{
private:
// -------------------------------------------------------------------- Private Typedefs
using Atomic_t = std::atomic_uint_fast32_t;
public:
// -------------------------------------------------------------------- Public Typedefs
using Refcount_t = uint_fast32_t;
private:
// -------------------------------------------------------------------- Friend Classes
friend class SmartPtr_Base;
// -------------------------------------------------------------------- State
mutable Atomic_t _reference_count;
mutable Mutex_t _object_mutex;
public:
// ==================================================================== Construct / Destruct
// Construct / Destruct
// -------------------------------------------------------------------- Construct
SmartObject() noexcept
: _reference_count(0) {}
// -------------------------------------------------------------------- Destruct
virtual ~SmartObject() {}
private:
// ==================================================================== Private API
// Private API
// -------------------------------------------------------------------- Reference Counting
inline void Reference_Increment() noexcept { _reference_count.fetch_add(1, std::memory_order_relaxed); }
inline Refcount_t Reference_Decrement() noexcept { return _reference_count.fetch_sub(1, std::memory_order_acq_rel) - 1; }
inline Refcount_t Reference_Count () const noexcept { return _reference_count.load(); }
};
};
#endif
//
// SmartPtr.h
//
#ifndef Tools_Core_SmartPtr_h
#define Tools_Core_SmartPtr_h
// ================================================================================ Standard Includes
// Standard Includes
// --------------------------------------------------------------------------------
#include <utility>
// ================================================================================ Tools Includes
// Tools Includes
// --------------------------------------------------------------------------------
#include "SmartObject.h"
namespace Core
{
// ============================================================================ SmartPtr_Base
// SmartPtr_Base
//
// Helper object for SmartPtr template, do not use directly.
// ----------------------------------------------------------------------------
class SmartPtr_Base
{
public:
static inline void Reference_Increment ( SmartObject * object_ptr ) noexcept { if ( object_ptr ) object_ptr->Reference_Increment(); }
static inline SmartObject::Refcount_t Reference_Decrement ( SmartObject * object_ptr ) noexcept { return ( object_ptr ) ? object_ptr->Reference_Decrement() : 0; }
static inline SmartObject::Refcount_t Reference_Count ( SmartObject * object_ptr ) noexcept { return ( object_ptr ) ? object_ptr->Reference_Count() : 0; }
};
// ============================================================================ SmartPtr
// SmartPtr
//
// Provides a reference-counting smart pointer for SmartObject-derived classes
// ----------------------------------------------------------------------------
template < class class_t >
class SmartPtr final : private SmartPtr_Base
{
private:
// -------------------------------------------------------------------- State
class_t * _object_ptr;
public:
// ==================================================================== Construct / Destruct
// Construct / Destruct
// -------------------------------------------------------------------- Construct
SmartPtr() noexcept : _object_ptr( nullptr ) {}
SmartPtr( class_t * object_ptr ) noexcept : _object_ptr( object_ptr ) { SmartPtr_Base::Reference_Increment( _object_ptr ); }
// -------------------------------------------------------------------- Construct ( convert )
template < class rhs_class_t >
SmartPtr( SmartPtr< rhs_class_t > & rhs ) noexcept
: _object_ptr( rhs.Get() )
{
SmartPtr_Base::Reference_Increment( _object_ptr );
}
// -------------------------------------------------------------------- Construct ( move/copy )
SmartPtr( SmartPtr const & source ) noexcept : _object_ptr( source._object_ptr ) { SmartPtr_Base::Reference_Increment( _object_ptr ); }
SmartPtr( SmartPtr && source ) noexcept : _object_ptr( source._object_ptr ) { source._object_ptr = nullptr; }
// -------------------------------------------------------------------- Destruct
~SmartPtr()
{
// If no object, then nothing to destruct
if ( _object_ptr == nullptr )
return;
// Decrement reference count, and delete object if necessary
const SmartObject::Refcount_t ref_count = SmartPtr_Base::Reference_Decrement( _object_ptr );
if ( !ref_count )
delete _object_ptr;
// Sanity
_object_ptr = nullptr;
}
public:
// ==================================================================== Public API
// Public API
// -------------------------------------------------------------------- Assignment
SmartPtr & operator=( SmartPtr const & source ) { SmartPtr(source ).Swap(*this); return *this; }
SmartPtr & operator=( SmartPtr && source ) { SmartPtr(std::forward<SmartPtr>(source)).Swap(*this); return *this; }
SmartPtr & operator=( class_t * source ) { SmartPtr(source ).Swap(*this); return *this; }
// -------------------------------------------------------------------- Dereference
class_t & operator* () const { return *_object_ptr; }
class_t * operator->() const { return _object_ptr; }
// -------------------------------------------------------------------- Pointer Access
class_t * Get() const noexcept { return _object_ptr; }
private:
// ==================================================================== Private API
// Private API
// -------------------------------------------------------------------- Swap()
void Swap( SmartPtr & source )
{
std::swap( _object_ptr, source._object_ptr );
}
};
// ============================================================================ SmartPtr Comparison Operators
// SmartPtr Comparison Operators
//
// I apologize for the wide code.
// ---------------------------------------------------------------------------- operator==()
template < class class1_t, class class2_t > inline bool operator==( SmartPtr<class1_t> const & sp1, SmartPtr<class2_t> const & sp2 ) { return sp1.Get() == sp2.Get(); }
template < class class1_t, class class2_t > inline bool operator==( SmartPtr<class1_t> const & sp1, class2_t * p2 ) { return sp1.Get() == p2; }
template < class class1_t, class class2_t > inline bool operator==( class1_t * p1, SmartPtr<class2_t> const & sp2 ) { return p1 == sp2.Get(); }
// ---------------------------------------------------------------------------- operator!=()
template < class class1_t, class class2_t > inline bool operator!=( SmartPtr<class1_t> const & sp1, SmartPtr<class2_t> const & sp2 ) { return sp1.Get() != sp2.Get(); }
template < class class1_t, class class2_t > inline bool operator!=( SmartPtr<class1_t> const & sp1, class2_t * p2 ) { return sp1.Get() != p2; }
template < class class1_t, class class2_t > inline bool operator!=( class1_t * p1, SmartPtr<class2_t> const & sp2 ) { return p1 != sp2.Get(); }
// ---------------------------------------------------------------------------- operator<()
template < class class_t >
inline bool operator<( SmartPtr<class_t> const & sp1,
SmartPtr<class_t> const & sp2 )
{
return std::less< class_t* >( sp1.Get(), sp2.Get() );
}
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment