//--------------------------------------------------------------------- // Provide an non-intersive reference counting smart pointer template // Copyright (C) 2007 Charles S. Wilson // This file is part of the OptionParse library. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //--------------------------------------------------------------------- #ifndef OptionParse__ExternalCountedPtr_HEADER #define OptionParse__ExternalCountedPtr_HEADER #include #include namespace OptionParse { // forward declaration class OPTIONPARSE_IMPEXP ExternalCountedPtrBase; class OPTIONPARSE_IMPEXP ExternalCounter { private: unsigned count; public: ExternalCounter(unsigned c = 1) : count(c) {} friend class ExternalCountedPtrBase; }; class OPTIONPARSE_IMPEXP ExternalCountedPtrBase { protected: ExternalCounter* theCounter; // managed by derived class virtual void deleteTarget(void ) throw() = 0; virtual void assignTarget(void*) throw() = 0; const unsigned countVal(void) const { return (theCounter ? theCounter->count : 0); } // derived class should only call this method immediately // after calling release(), or in constructor void acquire(ExternalCounter* c, void* p) throw() { // increment the count theCounter = c; if (c) { ++c->count; assignTarget(p); } } void release() { // decrement the count, delete if it is 0 if (theCounter) { if (--theCounter->count == 0) { deleteTarget(); delete theCounter; } theCounter = 0; } } // no default constructor ExternalCountedPtrBase(ExternalCounter* c) : theCounter(c) {} }; template class ExternalCountedPtr : public ExternalCountedPtrBase { private: X* thePtr; protected: // this should only be called by the release() method // in the base class. virtual void deleteTarget(void) throw() { if (thePtr) delete thePtr; thePtr = NULL; } virtual void assignTarget(void* p) throw() { thePtr = static_cast(p); } public: typedef X element_type; explicit ExternalCountedPtr(X* p = 0) // allocate a new counter : ExternalCountedPtrBase(0), thePtr(p) { if (p) theCounter = new ExternalCounter(); } virtual ~ExternalCountedPtr() { release(); } ExternalCountedPtr(const ExternalCountedPtr& r) : ExternalCountedPtrBase(0), thePtr(NULL) { acquire(r.theCounter, r.thePtr); } ExternalCountedPtr& operator=(const ExternalCountedPtr& r) { if (this != &r) { release(); acquire(r.theCounter, r.thePtr); } return *this; } bool operator==(const ExternalCountedPtr& rhs) const { return (thePtr == rhs.thePtr); } bool operator!=(const ExternalCountedPtr& rhs) const { return (thePtr != rhs.thePtr); } bool operator <(const ExternalCountedPtr& rhs) const { return (thePtr < rhs.thePtr); } template friend class ExternalCountedPtr; template ExternalCountedPtr(const ExternalCountedPtr& r) : ExternalCountedPtrBase(0), thePtr(NULL) // do NOT want to assign here, before count incremented { X* ptr = dynamic_cast(r.thePtr); if (ptr) { acquire(r.theCounter, ptr); } } template ExternalCountedPtr& operator=(const ExternalCountedPtr& r) { if (this != &r) { release(); X* ptr = dynamic_cast(r.thePtr); if (ptr) { acquire(r.theCounter, ptr); } } return *this; } X& operator*() const { if (isNotNull()) return *thePtr; else throw std::range_error("Operator* access to a null pointer is not allowed."); } X* operator->() const { if (isNotNull()) return thePtr; else throw std::range_error("Operator-> access to a null pointer is not allowed."); } X* get() const throw() {return thePtr; } bool unique() const throw() {return (countVal() == 1 || countVal() == 0); } bool isNull() const throw() {return (!theCounter || !thePtr); } bool isNotNull() const throw() {return !isNull(); } void nullify() throw() { release(); assignTarget(NULL); } }; } // namespace OptionParse #endif // OptionParse__ExternalCountedPtr_HEADER