Added array handling to SmartPtr.

git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1109 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
rich_sposato 2011-09-20 22:33:34 +00:00
parent 419efb2c20
commit 80a07d19e8
2 changed files with 153 additions and 7 deletions

View file

@ -355,6 +355,45 @@ namespace Loki
inline typename LockedStorage<T>::StoredType& GetImplRef(LockedStorage<T>& 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 T>
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 <class U>
ArrayStorage(const ArrayStorage<U>&) : 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_); }
{
DeleteArrayBase::Swap( rhs );
::std::swap( pointee_, rhs.pointee_ );
}
// Accessors
template <class F>
@ -844,6 +887,8 @@ namespace Loki
NoCheck()
{}
NoCheck( const NoCheck & ) {}
template <class P1>
NoCheck(const NoCheck<P1>&)
{}
@ -878,6 +923,8 @@ namespace Loki
AssertCheck()
{}
AssertCheck( const AssertCheck & ) {}
template <class P1>
AssertCheck(const AssertCheck<P1>&)
{}
@ -916,6 +963,8 @@ namespace Loki
AssertCheckStrict()
{}
AssertCheckStrict( const AssertCheckStrict & ) {}
template <class U>
AssertCheckStrict(const AssertCheckStrict<U>&)
{}
@ -972,6 +1021,8 @@ namespace Loki
RejectNullStatic()
{}
RejectNullStatic( const RejectNullStatic & ) {}
template <class P1>
RejectNullStatic(const RejectNullStatic<P1>&)
{}
@ -1022,6 +1073,8 @@ namespace Loki
RejectNull()
{}
RejectNull( const RejectNull & ) {}
template <class P1>
RejectNull(const RejectNull<P1>&)
{}
@ -1058,6 +1111,8 @@ namespace Loki
RejectNullStrict()
{}
RejectNullStrict( const RejectNullStrict & ) {}
template <class P1>
RejectNullStrict(const RejectNullStrict<P1>&)
{}
@ -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; }

View file

@ -21,6 +21,9 @@
#include <cassert>
#include <stdexcept>
#include <string>
//#define DO_EXTRA_LOKI_TESTS
#ifdef DO_EXTRA_LOKI_TESTS
#include <iostream>
@ -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_ )