Sans Pareil Technologies, Inc.

Key To Your Business

AutoPtr



The AutoPtr implementation is taken from the Poco project. Auto pointers are used when we have functions that return objects that are newly created on the heap. This removes the necessity for callers to keep track of usage and delete after use.

AutoPtr.h

The definition of the AutoPtr class.

    1: /*
    2: * AutoPtr.h
    3: *
    4: * Definition of the AutoPtr template class.
    5: *
    6: * Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
    7: * and Contributors.
    8: *
    9: * Permission is hereby granted, free of charge, to any person or organization
   10: * obtaining a copy of the software and accompanying documentation covered by
   11: * this license (the "Software") to use, reproduce, display, distribute,
   12: * execute, and transmit the Software, and to prepare derivative works of the
   13: * Software, and to permit third-parties to whom the Software is furnished to
   14: * do so, all subject to the following:
   15: *
   16: * The copyright notices in the Software and this entire statement, including
   17: * the above license grant, this restriction and the following disclaimer,
   18: * must be included in all copies of the Software, in whole or in part, and
   19: * all derivative works of the Software, unless such copies or derivative
   20: * works are solely in the form of machine-executable object code generated by
   21: * a source language processor.
   22: *
   23: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   24: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   25: * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
   26: * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
   27: * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
   28: * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   29: * DEALINGS IN THE SOFTWARE.
   30: */
   31:
   32: #ifndef SPT_AUTOPTR
   33: #define SPT_AUTOPTR
   34:
   35: #if defined( ARDUINO )
   36: #include "../StandardCplusplus/algorithm"
   37: #else
   38: #include <algorithm>
   39: #endif
   40:
   41: namespace spt
   42: {
   43:   /**
   44:    * @brief AutoPtr is a "smart" pointer for classes implementing reference counting based garbage collection.
   45:    *
   46:    * To be usable with the AutoPtr template, a class must
   47:    * implement the following behaviour:
   48:    *
   49:    * - A class must maintain a reference count.
   50:    * - The constructors of the object initialize the reference count to one.
   51:    * - The class must implement a public duplicate() method:
   52:    *     void duplicate();
   53:    * that increments the reference count by one.
   54:    * - The class must implement a public release() method:
   55:    *     void release()
   56:    * that decrements the reference count by one, and,
   57:    * if the reference count reaches zero, deletes the
   58:    * object.
   59:    *
   60:    * AutoPtr works in the following way:
   61:    * - If an AutoPtr is assigned an ordinary pointer to
   62:    * an object (via the constructor or the assignment operator),
   63:    * it takes ownership of the object and the object's reference
   64:    * count remains unchanged.
   65:    * - If the AutoPtr is assigned another AutoPtr, the
   66:    * object's reference count is incremented by one by
   67:    * calling duplicate() on its object.
   68:    * - The destructor of AutoPtr calls release() on its
   69:    * object.
   70:    * - AutoPtr supports dereferencing with both the ->
   71:    * and the * operator. An attempt to dereference a null
   72:    * AutoPtr results in a error that will cause application termination.
   73:    * AutoPtr also implements all relational operators.
   74:    * Note that AutoPtr allows casting of its encapsulated data types.
   75:   */
   76:   template <class C>
   77:   class AutoPtr
   78:   {
   79:   public:
   80:     /// Default constructor.  Creates a new instance that points to nothing
   81:     AutoPtr() : _ptr( NULL ) {}
   82:
   83:     /// Create an auto pointer that takes ownership of the specified pointer
   84:     AutoPtr( C* ptr ) : _ptr( ptr ) {}
   85:
   86:     /**
   87:      * @brief AutoPtr Create an auto pointer that takes ownership of the specified pointer
   88:      * @param ptr The pointer to take ownership of
   89:      * @param shared If \c true then increment the reference count for the
   90:      *   specified pointer.
   91:      */
   92:     AutoPtr( C* ptr, bool shared ) : _ptr( ptr )
   93:     {
   94:       if ( shared && _ptr ) _ptr->duplicate();
   95:     }
   96:
   97:     /// Copy constructor.  Increases the reference count for the owned object.
   98:     AutoPtr( const AutoPtr& ptr ) : _ptr( ptr._ptr )
   99:     {
  100:       if ( _ptr ) _ptr->duplicate();
  101:     }
  102:
  103:     /// Copy constructor for taking ownership of another type of object
  104:     template <class Other>
  105:     AutoPtr( const AutoPtr<Other>& ptr ) : _ptr( const_cast<Other*>( ptr.get() ) )
  106:     {
  107:       if ( _ptr ) _ptr->duplicate();
  108:     }
  109:
  110:     /// Destructor.  Invokes \c release on the owned object.
  111:     ~AutoPtr() { if ( _ptr ) _ptr->release(); }
  112:
  113:     /// Use to (re)set the owned object.  If current owned object is not
  114:     /// \c null, invokes \c release on the object.
  115:     AutoPtr& assign( C* ptr )
  116:     {
  117:       if ( _ptr != ptr )
  118:       {
  119:         if ( _ptr ) _ptr->release();
  120:         _ptr = ptr;
  121:       }
  122:
  123:       return *this;
  124:     }
  125:
  126:     /**
  127:      * @brief Reset the owned object.  If current owned object is not
  128:      * \c null, invokes \c release on the object.  Will invoke \c duplicate
  129:      * on the new instance if \c shared is specified
  130:      * @param ptr The new object to take ownership of.
  131:      * @param shared If \c true, \c duplicate() the owned object.
  132:      * @return Reference to this instance for convenience.
  133:      */
  134:     AutoPtr& assign( C* ptr, bool shared )
  135:     {
  136:       if ( _ptr != ptr )
  137:       {
  138:         if ( _ptr ) _ptr->release();
  139:         _ptr = ptr;
  140:         if (shared && _ptr) _ptr->duplicate();
  141:       }
  142:       return *this;
  143:     }
  144:
  145:     /// Share the pointer owned by the specified auto pointer instance.
  146:     AutoPtr& assign( const AutoPtr& ptr )
  147:     {
  148:       if ( &ptr != this )
  149:       {
  150:         if ( _ptr ) _ptr->release();
  151:         _ptr = ptr._ptr;
  152:         if ( _ptr ) _ptr->duplicate();
  153:       }
  154:
  155:       return *this;
  156:     }
  157:
  158:     /// Share the pointer owned by the specified auto pointer of different type.
  159:     template <class Other>
  160:     AutoPtr& assign( const AutoPtr<Other>& ptr )
  161:     {
  162:       if ( ptr.get() != _ptr )
  163:       {
  164:         if ( _ptr ) _ptr->release();
  165:         _ptr = const_cast<Other*>( ptr.get() );
  166:         if ( _ptr ) _ptr->duplicate();
  167:       }
  168:
  169:       return *this;
  170:     }
  171:
  172:     /// Copy assignment operator.  Delegates to {@link #assign}.
  173:     AutoPtr& operator = ( C* ptr )
  174:     {
  175:       return assign( ptr );
  176:     }
  177:
  178:     /// Copy assignment operator.  Delegates to {@link #assign}.
  179:     AutoPtr& operator = ( const AutoPtr& ptr )
  180:     {
  181:       return assign( ptr );
  182:     }
  183:
  184:     /// Copy assignment operator.  Delegates to {@link #assign}.
  185:     template <class Other>
  186:     AutoPtr& operator = ( const AutoPtr<Other>& ptr )
  187:     {
  188:       return assign<Other>(ptr);
  189:     }
  190:
  191:     /// Swap the pointers of this instance with the specified instance.
  192:     void swap( AutoPtr& ptr )
  193:     {
  194:       std::swap( _ptr, ptr._ptr );
  195:     }
  196:
  197:     /// Casts the AutoPtr via a dynamic cast to the given type.
  198:     /// Returns an AutoPtr containing NULL if the cast fails.
  199:     /// Example: (assume class Sub: public Super)
  200:     ///    AutoPtr<Super> super(new Sub());
  201:     ///    AutoPtr<Sub> sub = super.cast<Sub>();
  202:     ///    poco_assert (sub.get());
  203:     template <class Other>
  204:     AutoPtr<Other> cast() const
  205:     {
  206:       Other* pOther = dynamic_cast<Other*>( _ptr );
  207:       return AutoPtr<Other>( pOther, true );
  208:     }
  209:
  210:     /// Casts the AutoPtr via a static cast to the given type.
  211:     /// Example: (assume class Sub: public Super)
  212:     ///    AutoPtr<Super> super(new Sub());
  213:     ///    AutoPtr<Sub> sub = super.unsafeCast<Sub>();
  214:     ///    poco_assert (sub.get());
  215:     template <class Other>
  216:     AutoPtr<Other> unsafeCast() const
  217:     {
  218:       Other* pOther = static_cast<Other*>(_ptr);
  219:       return AutoPtr<Other>(pOther, true);
  220:     }
  221:
  222:     /// Pointer acess operator for the owned object.  Returns \c NULL if invalid
  223:     C* operator -> () { return _ptr; }
  224:
  225:     /// Pointer acess operator for the owned object.  Returns \c NULL if invalid
  226:     const C* operator -> () const { return _ptr; }
  227:
  228:     /// Dereference operator for the owned object.  Will lead to program
  229:     /// termination if the owned object is not valid
  230:     C& operator * () { return *_ptr; }
  231:
  232:     /// Dereference operator for the owned object.  Will lead to program
  233:     /// termination if the owned object is not valid
  234:     const C& operator * () const { return *_ptr; }
  235:
  236:     /// Return the owned pointer.  Callers must not \c delete
  237:     C* get() { return _ptr; }
  238:
  239:     /// Return the owned pointer.  Callers must not \c delete
  240:     const C* get() const { return _ptr; }
  241:
  242:     /// Function operator.  Return the owned pointer
  243:     operator C* () { return _ptr; }
  244:
  245:     /// Function operator.  Return the owned pointer
  246:     operator const C* () const { return _ptr; }
  247:
  248:     /// Negative check of make sure the owned pointer is not valid.
  249:     bool operator ! () const { return _ptr == 0; }
  250:
  251:     /// Negative check of make sure the owned pointer is not valid.
  252:     bool isNull() const { return _ptr == 0; }
  253:
  254:     /// Invokes \c duplicate() on the owned pointer if valid.
  255:     C* duplicate()
  256:     {
  257:       if ( _ptr ) _ptr->duplicate();
  258:       return _ptr;
  259:     }
  260:
  261:     /// Compare the owned objects for equality
  262:     bool operator == ( const AutoPtr& ptr ) const
  263:     {
  264:       return _ptr == ptr._ptr;
  265:     }
  266:
  267:     /// Compare the owned object against the specified object for equality
  268:     bool operator == ( const C* ptr ) const { return _ptr == ptr; }
  269:
  270:     /// Compare the owned object against the specified object for equality
  271:     bool operator == (C* ptr) const { return _ptr == ptr; }
  272:
  273:     /// Compare the owned objects for inequality
  274:     bool operator != (const AutoPtr& ptr) const
  275:     {
  276:       return _ptr != ptr._ptr;
  277:     }
  278:
  279:     /// Compare the owned object against the specified object for inequality
  280:     bool operator != ( const C* ptr ) const { return _ptr != ptr; }
  281:
  282:     /// Compare the owned object against the specified object for inequality
  283:     bool operator != ( C* ptr ) const { return _ptr != ptr; }
  284:
  285:     /// Compare the owned objects for ordering
  286:     bool operator < ( const AutoPtr& ptr ) const
  287:     {
  288:       return _ptr < ptr._ptr;
  289:     }
  290:
  291:     /// Compare the owned object against the specified object for ordering
  292:     bool operator < ( const C* ptr ) const { return _ptr < ptr; }
  293:
  294:     /// Compare the owned object against the specified object for ordering
  295:     bool operator < ( C* ptr ) const { return _ptr < ptr; }
  296:
  297:     bool operator <= ( const AutoPtr& ptr ) const
  298:     {
  299:       return _ptr <= ptr._ptr;
  300:     }
  301:
  302:     bool operator <= ( const C* ptr ) const { return _ptr <= ptr; }
  303:
  304:     bool operator <= ( C* ptr ) const { return _ptr <= ptr; }
  305:
  306:     bool operator > ( const AutoPtr& ptr ) const
  307:     {
  308:       return _ptr > ptr._ptr;
  309:     }
  310:
  311:     bool operator > ( const C* ptr ) const { return _ptr > ptr; }
  312:
  313:     bool operator > ( C* ptr ) const { return _ptr > ptr; }
  314:
  315:     bool operator >= ( const AutoPtr& ptr ) const
  316:     {
  317:       return _ptr >= ptr._ptr;
  318:     }
  319:
  320:     bool operator >= ( const C* ptr ) const { return _ptr >= ptr; }
  321:
  322:     bool operator >= ( C* ptr ) const { return _ptr >= ptr; }
  323:
  324:   private:
  325:     C* _ptr;
  326:   };
  327:
  328:
  329:   template <class C>
  330:   inline void swap( AutoPtr<C>& p1, AutoPtr<C>& p2 )
  331:   {
  332:     p1.swap( p2 );
  333:   }
  334:
  335: } // namespace spt
  336:
  337:
  338: #endif // SPT_AUTOPTR



AutoPtrTest.cpp

The unit test suite for the AutoPtr class.

    1: #if defined( ARDUINO )
    2: #include "AutoPtr.h"
    3: #include "tut.hpp"
    4: #else
    5: #include <AutoPtr.h>
    6: #include <tut/tut.hpp>
    7: #endif
    8:
    9: namespace spt
   10: {
   11:   namespace autoptr
   12:   {
   13:     class TestObj
   14:     {
   15:     public:
   16:       TestObj(): _rc(1)
   17:       {
   18:         ++_count;
   19:       }
   20:
   21:       void duplicate()
   22:       {
   23:         ++_rc;
   24:       }
   25:
   26:       void release()
   27:       {
   28:         if (--_rc == 0)
   29:           delete this;
   30:       }
   31:
   32:       int rc() const
   33:       {
   34:         return _rc;
   35:       }
   36:
   37:       static int count()
   38:       {
   39:         return _count;
   40:       }
   41:
   42:     protected:
   43:       ~TestObj()
   44:       {
   45:         --_count;
   46:       }
   47:
   48:     private:
   49:       int _rc;
   50:       static int _count;
   51:     };
   52:
   53:     int TestObj::_count = 0;
   54:   }
   55: }
   56:
   57: using spt::AutoPtr;
   58: using spt::autoptr::TestObj;
   59:
   60: namespace tut
   61: {
   62:   struct AutoPtrTestData {};
   63:
   64:
   65:   typedef test_group<AutoPtrTestData> AutoPtrTestGroup;
   66:   typedef AutoPtrTestGroup::object AutoPtrTest;
   67:   AutoPtrTestGroup autoPtrTestGroup( "AutoPtr test suite" );
   68:
   69:
   70:   template<>
   71:   template<>
   72:   void AutoPtrTest::test<1>()
   73:   {
   74:     set_test_name( "basic" );
   75:
   76:     {
   77:       AutoPtr<TestObj> ptr = new TestObj;
   78:       ensure(ptr->rc() == 1);
   79:       AutoPtr<TestObj> ptr2 = ptr;
   80:       ensure (ptr->rc() == 2);
   81:       ptr2 = new TestObj;
   82:       ensure (ptr->rc() == 1);
   83:       AutoPtr<TestObj> ptr3;
   84:       ptr3 = ptr2;
   85:       ensure (ptr2->rc() == 2);
   86:       ptr3 = new TestObj;
   87:       ensure (ptr2->rc() == 1);
   88:       ptr3 = ptr2;
   89:       ensure (ptr2->rc() == 2);
   90:       ensure (TestObj::count() > 0);
   91:     }
   92:
   93:     ensure( TestObj::count() == 0 );
   94:   }
   95:
   96:
   97:   template<>
   98:   template<>
   99:   void AutoPtrTest::test<2>()
  100:   {
  101:     set_test_name( "operations" );
  102:
  103:     AutoPtr<TestObj> ptr1;
  104:     ensure( ptr1.get() == NULL );
  105:     TestObj* pTO1 = new TestObj;
  106:     TestObj* pTO2 = new TestObj;
  107:     if (pTO2 < pTO1)
  108:     {
  109:       TestObj* pTmp = pTO1;
  110:       pTO1 = pTO2;
  111:       pTO2 = pTmp;
  112:     }
  113:     ensure (pTO1 < pTO2);
  114:     ptr1 = pTO1;
  115:     AutoPtr<TestObj> ptr2 = pTO2;
  116:     AutoPtr<TestObj> ptr3 = ptr1;
  117:     AutoPtr<TestObj> ptr4;
  118:     ensure (ptr1.get() == pTO1);
  119:     ensure (ptr1 == pTO1);
  120:     ensure (ptr2.get() == pTO2);
  121:     ensure (ptr2 == pTO2);
  122:     ensure (ptr3.get() == pTO1);
  123:     ensure (ptr3 == pTO1);
  124:
  125:     ensure (ptr1 == pTO1);
  126:     ensure (ptr1 != pTO2);
  127:     ensure (ptr1 < pTO2);
  128:     ensure (ptr1 <= pTO2);
  129:     ensure (ptr2 > pTO1);
  130:     ensure (ptr2 >= pTO1);
  131:
  132:     ensure (ptr1 == ptr3);
  133:     ensure (ptr1 != ptr2);
  134:     ensure (ptr1 < ptr2);
  135:     ensure (ptr1 <= ptr2);
  136:     ensure (ptr2 > ptr1);
  137:     ensure (ptr2 >= ptr1);
  138:
  139:     ptr1 = pTO1;
  140:     ptr2 = pTO2;
  141:     ptr1.swap(ptr2);
  142:     ensure (ptr2.get() == pTO1);
  143:     ensure (ptr1.get() == pTO2);
  144:
  145:     ensure (!(ptr4 == ptr1));
  146:     ensure (!(ptr4 == ptr2));
  147:     ensure (ptr4 != ptr1);
  148:     ensure (ptr4 != ptr2);
  149:
  150:     ptr4 = ptr2;
  151:     ensure (ptr4 == ptr2);
  152:     ensure (!(ptr4 != ptr2));
  153:
  154:     ensure (!(!ptr1));
  155:     ptr1 = 0;
  156:     ensure (!ptr1);
  157:   }
  158: }