// // AutoPtr.h // // $Id: //poco/1.4/Foundation/include/Poco/AutoPtr.h#1 $ // // Library: Foundation // Package: Core // Module: AutoPtr // // Definition of the AutoPtr template class. // // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. // and Contributors. // // Permission is hereby granted, free of charge, to any person or organization // obtaining a copy of the software and accompanying documentation covered by // this license (the "Software") to use, reproduce, display, distribute, // execute, and transmit the Software, and to prepare derivative works of the // Software, and to permit third-parties to whom the Software is furnished to // do so, all subject to the following: // // The copyright notices in the Software and this entire statement, including // the above license grant, this restriction and the following disclaimer, // must be included in all copies of the Software, in whole or in part, and // all derivative works of the Software, unless such copies or derivative // works are solely in the form of machine-executable object code generated by // a source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // #ifndef Foundation_AutoPtr_INCLUDED #define Foundation_AutoPtr_INCLUDED #include "Poco/Foundation.h" #include "Poco/Exception.h" #include #include // for std::less, greater, etc namespace Poco { template class AutoPtr /// AutoPtr is a "smart" pointer for classes implementing /// reference counting based garbage collection. /// To be usable with the AutoPtr template, a class must /// implement the following behaviour: /// A class must maintain a reference count. /// The constructors of the object initialize the reference /// count to one. /// The class must implement a public duplicate() method: /// void duplicate(); /// that increments the reference count by one. /// The class must implement a public release() method: /// void release() /// that decrements the reference count by one, and, /// if the reference count reaches zero, deletes the /// object. /// /// AutoPtr works in the following way: /// If an AutoPtr is assigned an ordinary pointer to /// an object (via the constructor or the assignment operator), /// it takes ownership of the object and the object's reference /// count remains unchanged. /// If the AutoPtr is assigned another AutoPtr, the /// object's reference count is incremented by one by /// calling duplicate() on its object. /// The destructor of AutoPtr calls release() on its /// object. /// AutoPtr supports dereferencing with both the -> /// and the * operator. An attempt to dereference a null /// AutoPtr results in a NullPointerException being thrown. /// AutoPtr also implements all relational operators. /// Note that AutoPtr allows casting of its encapsulated data types. { public: AutoPtr(): _ptr(0) { } AutoPtr(C* ptr): _ptr(ptr) { } AutoPtr(C* ptr, bool shared): _ptr(ptr) { if (shared && _ptr) _ptr->duplicate(); } AutoPtr(const AutoPtr& ptr): _ptr(ptr._ptr) { if (_ptr) _ptr->duplicate(); } template AutoPtr(const AutoPtr& ptr): _ptr(ptr.get()) { if (_ptr) _ptr->duplicate(); } ~AutoPtr() { if (_ptr) _ptr->release(); } AutoPtr& assign(C* ptr) { if (_ptr != ptr) { if (_ptr) _ptr->release(); _ptr = ptr; } return *this; } AutoPtr& assign(C* ptr, bool shared) { if (_ptr != ptr) { if (_ptr) _ptr->release(); _ptr = ptr; if (shared && _ptr) _ptr->duplicate(); } return *this; } AutoPtr& assign(const AutoPtr& ptr) { if (&ptr != this) { if (_ptr) _ptr->release(); _ptr = ptr._ptr; if (_ptr) _ptr->duplicate(); } return *this; } template AutoPtr& assign(const AutoPtr& ptr) { if (ptr.get() != _ptr) { if (_ptr) _ptr->release(); _ptr = ptr.get(); if (_ptr) _ptr->duplicate(); } return *this; } AutoPtr& operator = (C* ptr) { return assign(ptr); } AutoPtr& operator = (const AutoPtr& ptr) { return assign(ptr); } template AutoPtr& operator = (const AutoPtr& ptr) { return assign(ptr); } void swap(AutoPtr& ptr) { std::swap(_ptr, ptr._ptr); } template AutoPtr cast() const /// Casts the AutoPtr via a dynamic cast to the given type. /// Returns an AutoPtr containing NULL if the cast fails. /// Example: (assume class Sub: public Super) /// AutoPtr super(new Sub()); /// AutoPtr sub = super.cast(); /// poco_assert (sub.get()); { Other* pOther = dynamic_cast(_ptr); return AutoPtr(pOther, true); } template AutoPtr unsafeCast() const /// Casts the AutoPtr via a static cast to the given type. /// Example: (assume class Sub: public Super) /// AutoPtr super(new Sub()); /// AutoPtr sub = super.unsafeCast(); /// poco_assert (sub.get()); { Other* pOther = static_cast(_ptr); return AutoPtr(pOther, true); } C* operator -> () const { if (_ptr) return _ptr; else throw NullPointerException(); } C& operator * () const { if (_ptr) return *_ptr; else throw NullPointerException(); } C* get() const { return _ptr; } // This also serves as an safe implicit conversion to a boolean type operator C* () const { return _ptr; } bool operator ! () const { return _ptr == 0; } bool isNull() const { return _ptr == 0; } C* duplicate() const { if (_ptr) _ptr->duplicate(); return _ptr; } private: C* _ptr; }; namespace Detail { // This class will generate a compilation error if the types T and U // can not be compared, i.e. they do not have a a composite // pointer type // Intentionaly complex to reduce the likeliness of warnings template struct EnsureHasCompositePointerType { static void constraints(T* a, U* b, bool& x) { // If you get a compilation error here, then you have // tried to compare two smart pointers with // unrelated types. x = a < b; } typedef void f_type(T*, U*, bool&); void no_op(f_type) { // empty on purpose } EnsureHasCompositePointerType() { // This assignment should be optimized away by the compiler void (*p)(T*, U*, bool&) = constraints; // To get rid of the warning that we do not use the // variable no_op(p); } }; // The use of EnsureHasCompositePointerType, is done to ensure that // the pointers can be compared using the normal C++ language rules. // The reason the operators are not used directly is because // they are not required to give a total ordering for objects of any // type, however the predicates, eg. std::less, are required to give // a total ordering. template bool pointerLess(T* a, U* b) { EnsureHasCompositePointerType(); return std::less()(a, b); } template bool pointerLessEq(T* a, U* b) { EnsureHasCompositePointerType(); return std::less_equal()(a, b); } template bool pointerGreater(T* a, U* b) { EnsureHasCompositePointerType(); return std::greater()(a, b); } template bool pointerGreaterEq(T* a, U* b) { EnsureHasCompositePointerType(); return std::greater_equal()(a, b); } } template inline void swap(AutoPtr& p1, AutoPtr& p2) { p1.swap(p2); } template bool operator == (const AutoPtr& a, const AutoPtr& b) { return a.get() == b.get(); } template bool operator == (T* a, const AutoPtr& b) { return a == b.get(); } template bool operator == (const AutoPtr& a, U* b) { return a.get() == b; } template bool operator != (const AutoPtr& a, const AutoPtr& b) { return a.get() != b.get(); } template bool operator != (T* a, const AutoPtr& b) { return a != b.get(); } template bool operator != (const AutoPtr& a, U* b) { return a.get() != b; } template bool operator < (const AutoPtr& a, const AutoPtr& b) { return Detail::pointerLess(a.get(), b.get()); } template bool operator < (T* a, const AutoPtr& b) { return Detail::pointerLess(a, b.get()); } template bool operator < (const AutoPtr& a, U* b) { return Detail::pointerLess(a.get(), b); } template bool operator <= (const AutoPtr& a, const AutoPtr& b) { return Detail::pointerLessEq(a.get(), b.get()); } template bool operator <= (T* a, const AutoPtr& b) { return Detail::pointerLessEq(a, b.get()); } template bool operator <= (const AutoPtr& a, U* b) { return Detail::pointerLessEq(a.get(), b); } template bool operator > (const AutoPtr& a, const AutoPtr& b) { return Detail::pointerGreater(a.get(), b.get()); } template bool operator > (T* a, const AutoPtr& b) { return Detail::pointerGreater(a, b.get()); } template bool operator > (const AutoPtr& a, U* b) { return Detail::pointerGreater(a.get(), b); } template bool operator >= (const AutoPtr& a, const AutoPtr& b) { return Detail::pointerGreaterEq(a.get(), b.get()); } template bool operator >= (T* a, const AutoPtr& b) { return Detail::pointerGreaterEq(a, b.get()); } template bool operator >= (const AutoPtr& a, U* b) { return Detail::pointerGreaterEq(a.get(), b); } } // namespace Poco #endif // Foundation_AutoPtr_INCLUDED