From 80a07d19e8d2540cc7cb2ecc43a9550f55101c84 Mon Sep 17 00:00:00 2001 From: rich_sposato Date: Tue, 20 Sep 2011 22:33:34 +0000 Subject: [PATCH] Added array handling to SmartPtr. git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1109 7ec92016-0320-0410-acc4-a06ded1c099a --- include/loki/SmartPtr.h | 118 +++++++++++++++++++++++++++++++++++++--- src/SmartPtr.cpp | 42 ++++++++++++++ 2 files changed, 153 insertions(+), 7 deletions(-) diff --git a/include/loki/SmartPtr.h b/include/loki/SmartPtr.h index 80d230f..aaf5d40 100644 --- a/include/loki/SmartPtr.h +++ b/include/loki/SmartPtr.h @@ -355,6 +355,45 @@ namespace Loki inline typename LockedStorage::StoredType& GetImplRef(LockedStorage& sp) { return sp.pointee_; } + namespace Private + { + + //////////////////////////////////////////////////////////////////////////////// + /// \class DeleteArrayBase + /// + /// \ingroup StrongPointerDeleteGroup + /// Base class used only by the DeleteArray policy class. This stores the + /// number of elements in an array of shared objects. + //////////////////////////////////////////////////////////////////////////////// + + class DeleteArrayBase + { + public: + + inline size_t GetArrayCount( void ) const { return m_itemCount; } + + protected: + + DeleteArrayBase( void ) : m_itemCount( 0 ) {} + + explicit DeleteArrayBase( size_t itemCount ) : m_itemCount( itemCount ) {} + + DeleteArrayBase( const DeleteArrayBase & that ) : m_itemCount( that.m_itemCount ) {} + + void Swap( DeleteArrayBase & rhs ); + + void OnInit( const void * p ) const; + + void OnCheckRange( size_t index ) const; + + private: + + size_t m_itemCount; + + }; + + } + //////////////////////////////////////////////////////////////////////////////// /// \class ArrayStorage @@ -365,7 +404,7 @@ namespace Loki template - class ArrayStorage + class ArrayStorage : public ::Loki::Private::DeleteArrayBase { public: @@ -376,26 +415,30 @@ namespace Loki protected: - ArrayStorage() : pointee_(Default()) + ArrayStorage() : DeleteArrayBase(), pointee_(Default()) {} // The storage policy doesn't initialize the stored pointer // which will be initialized by the OwnershipPolicy's Clone fn - ArrayStorage(const ArrayStorage&) : pointee_(0) + ArrayStorage( const ArrayStorage & that ) : DeleteArrayBase( that ), pointee_( 0 ) {} template - ArrayStorage(const ArrayStorage&) : pointee_(0) + ArrayStorage( const ArrayStorage< U >& that ) : DeleteArrayBase( that ), pointee_( 0 ) {} - explicit ArrayStorage(const StoredType& p) : pointee_(p) {} + ArrayStorage( const StoredType & p, size_t count ) : DeleteArrayBase( count ), + pointee_( p ) {} PointerType operator->() const { return pointee_; } ReferenceType operator*() const { return *pointee_; } - void Swap(ArrayStorage& rhs) - { std::swap(pointee_, rhs.pointee_); } + void Swap( ArrayStorage & rhs ) + { + DeleteArrayBase::Swap( rhs ); + ::std::swap( pointee_, rhs.pointee_ ); + } // Accessors template @@ -844,6 +887,8 @@ namespace Loki NoCheck() {} + NoCheck( const NoCheck & ) {} + template NoCheck(const NoCheck&) {} @@ -878,6 +923,8 @@ namespace Loki AssertCheck() {} + AssertCheck( const AssertCheck & ) {} + template AssertCheck(const AssertCheck&) {} @@ -916,6 +963,8 @@ namespace Loki AssertCheckStrict() {} + AssertCheckStrict( const AssertCheckStrict & ) {} + template AssertCheckStrict(const AssertCheckStrict&) {} @@ -972,6 +1021,8 @@ namespace Loki RejectNullStatic() {} + RejectNullStatic( const RejectNullStatic & ) {} + template RejectNullStatic(const RejectNullStatic&) {} @@ -1022,6 +1073,8 @@ namespace Loki RejectNull() {} + RejectNull( const RejectNull & ) {} + template RejectNull(const RejectNull&) {} @@ -1058,6 +1111,8 @@ namespace Loki RejectNullStrict() {} + RejectNullStrict( const RejectNullStrict & ) {} + template RejectNullStrict(const RejectNullStrict&) {} @@ -1245,6 +1300,16 @@ namespace Loki KP::OnInit(GetImpl(*this)); } + /** This constructor was designed to only work with the ArrayStorage policy. Using it with + any other Delete policies will cause compiler errors. Call it with this syntax: + "ThingyPtr sp2( new Thingy[ 4 ], 4 );" so SmartPtr can do range checking on the number of elements. + */ + SmartPtr( ImplicitArg p, size_t itemCount ) : SP( p, itemCount ) + { + KP::OnInit( GetImpl( *this ) ); + SP::OnInit( GetImpl( *this ) ); + } + SmartPtr(CopyArg& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { KP::OnDereference( GetImpl( rhs ) ); @@ -1333,6 +1398,21 @@ namespace Loki return *this; } + /** This function is equivalent to an assignment operator for SmartPtr's that use the + DeleteArray policy where the programmer needs to write the equivalent of "sp = new P;". + With DeleteArray, the programmer should write "sp.Assign( new [5] Thingy, 5 );" so the + SmartPtr knows how many elements are in the array. + */ + SmartPtr & Assign( T * p, size_t itemCount ) + { + if ( GetImpl( *this ) != p ) + { + SmartPtr temp( p, itemCount ); + Swap( temp ); + } + return *this; + } + void Swap(SmartPtr& rhs) { OP::Swap(rhs); @@ -1465,6 +1545,30 @@ namespace Loki return SP::operator*(); } + /** operator[] returns a reference to an modifiable object. If the index is greater than or + equal to the number of elements, the function will throw a std::out_of_range exception. + This only works with DeleteArray policy. Any other policy will cause a compiler error. + */ + ReferenceType operator [] ( size_t index ) + { + PointerType p = SP::operator->(); + KP::OnDereference( p ); + SP::OnCheckRange( index ); + return p[ index ]; + } + + /** operator[] returns a reference to a const object. If the index is greater than or + equal to the number of elements, the function will throw a std::out_of_range exception. + This only works with DeleteArray policy. Any other policy will cause a compiler error. + */ + ConstReferenceType operator [] ( size_t index ) const + { + ConstPointerType p = SP::operator->(); + KP::OnDereference( p ); + SP::OnCheckRange( index ); + return p[ index ]; + } + bool operator!() const // Enables "if (!sp) ..." { return GetImpl(*this) == 0; } diff --git a/src/SmartPtr.cpp b/src/SmartPtr.cpp index 2b878f6..434dd84 100644 --- a/src/SmartPtr.cpp +++ b/src/SmartPtr.cpp @@ -21,6 +21,9 @@ #include +#include +#include + //#define DO_EXTRA_LOKI_TESTS #ifdef DO_EXTRA_LOKI_TESTS #include @@ -37,6 +40,45 @@ namespace Private // ---------------------------------------------------------------------------- +void DeleteArrayBase::Swap( DeleteArrayBase & rhs ) +{ + assert( NULL != this ); + + const size_t temp = m_itemCount; + m_itemCount = rhs.m_itemCount; + rhs.m_itemCount = temp; +} + +// ---------------------------------------------------------------------------- + +void DeleteArrayBase::OnInit( const void * p ) const +{ + assert( NULL != this ); + if ( NULL == p ) + { + assert( 0 == m_itemCount ); + } + else + { + assert( 0 < m_itemCount ); + } +} + +// ---------------------------------------------------------------------------- + +void DeleteArrayBase::OnCheckRange( size_t index ) const +{ + assert( NULL != this ); + + if ( index < m_itemCount ) + return; + + const ::std::string message( "index out of range in ::Loki::DeleteArrayBase::OnCheckRange" ); + throw ::std::out_of_range( message ); +} + +// ---------------------------------------------------------------------------- + RefLinkedBase::RefLinkedBase( const RefLinkedBase & rhs ) : prev_( &rhs ), next_( rhs.next_ )