/* * Copyright (c) 2002-2007 Daniel Elstner * * This file is part of regexxer. * * regexxer is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * regexxer 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with regexxer; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef REGEXXER_SHAREDPTR_H_INCLUDED #define REGEXXER_SHAREDPTR_H_INCLUDED #include namespace Util { template class SharedPtr; /* * Common base class of objects managed by SharedPtr<>. */ class SharedObject { protected: inline SharedObject(); // initial reference count is 0 inline ~SharedObject(); private: mutable long refcount_; // noncopyable SharedObject(const SharedObject&); SharedObject& operator=(const SharedObject&); template friend class SharedPtr; }; /* * Intrusive smart pointer implementation. It requires the managed types * to be derived from class SharedObject, in order to do reference counting * as efficient as possible. * * The intrusive approach also simplifies the implementation, particularly * with regards to exception safety. A non-intrusive smart pointer like * boost::shared_ptr<> would have to allocate memory to hold the reference * count -- this is tricky not only because of the 'new' which could throw, * but it also complicates the implementation of the cast templates like * shared_dynamic_cast<> etc. * * The cast template functions use the same syntax as in boost: * * shared_static_cast returns static_cast(pointer) * shared_dynamic_cast returns dynamic_cast(pointer) * shared_polymorphic_cast returns &dynamic_cast(*pointer) * * I didn't implement shared_polymorphic_downcast because it seems to be * just a debug check for those who don't want to ship with debugging enabled. * This would be silly IMHO, considering that the dynamic_cast<> overhead is * negligible in a GUI application like regexxer. * * About operator const void*() const: * * This operator fulfills the same task operator bool() would, but safer. * A SharedPtr<> will never be implicitely converted to an integer type, * which is particularly important in the context of overload resolution. * An additional advantage is that operator const void*() gets us equality * and non-equality tests for free. * * Note that boost is using an operator that converts to a PMF (pointer to * member function) for this purpose. However, I consider this solution * to be somewhat over the top. */ template class SharedPtr { public: inline SharedPtr(); inline ~SharedPtr(); explicit inline SharedPtr(T* ptr); // obtains reference inline SharedPtr(const SharedPtr& other); inline SharedPtr& operator=(const SharedPtr& other); template inline SharedPtr(const SharedPtr& other); template inline SharedPtr& operator=(const SharedPtr& other); inline void swap(SharedPtr& other); inline void reset(T* ptr = 0); // obtains reference inline T* get() const; inline T* operator->() const; inline T& operator*() const; inline operator const void*() const; private: T* ptr_; }; /* * Explicitely forbid the usage of a generic SharedPtr * because class SharedObject doesn't have a virtual destructor. */ template <> class SharedPtr {}; template <> class SharedPtr {}; inline SharedObject::SharedObject() : refcount_ (0) {} inline SharedObject::~SharedObject() {} template inline SharedPtr::SharedPtr() : ptr_ (0) {} template inline SharedPtr::~SharedPtr() { if (ptr_ && --ptr_->refcount_ <= 0) delete ptr_; } template inline SharedPtr::SharedPtr(T* ptr) : ptr_ (ptr) { if (ptr_) ++ptr_->refcount_; } /* * Note that reset() and get() are defined here and not in declaration order * on purpose -- defining them before their first use is required with some * compilers for for maximum inlining. */ template inline void SharedPtr::swap(SharedPtr& other) { std::swap(ptr_, other.ptr_); } template inline void SharedPtr::reset(T* ptr) { // Note that SharedPtr<>::reset() obtains a reference. SharedPtr temp (ptr); std::swap(ptr_, temp.ptr_); } template inline T* SharedPtr::get() const { return ptr_; } template inline SharedPtr::SharedPtr(const SharedPtr& other) : ptr_ (other.ptr_) { if (ptr_) ++ptr_->refcount_; } template inline SharedPtr& SharedPtr::operator=(const SharedPtr& other) { this->reset(other.ptr_); return *this; } template template inline SharedPtr::SharedPtr(const SharedPtr& other) : ptr_ (other.get()) { if (ptr_) ++ptr_->refcount_; } template template inline SharedPtr& SharedPtr::operator=(const SharedPtr& other) { this->reset(other.get()); return *this; } template inline T* SharedPtr::operator->() const { return ptr_; } template inline T& SharedPtr::operator*() const { return *ptr_; } template inline SharedPtr::operator const void*() const { return ptr_; } template inline void swap(SharedPtr& a, SharedPtr& b) { a.swap(b); } template inline SharedPtr shared_static_cast(const SharedPtr& other) { return SharedPtr(static_cast(other.get())); } template inline SharedPtr shared_dynamic_cast(const SharedPtr& other) { return SharedPtr(dynamic_cast(other.get())); } template inline SharedPtr shared_polymorphic_cast(const SharedPtr& other) { return SharedPtr(&dynamic_cast(*other)); // may throw std::bad_cast } } // namespace Util #endif /* REGEXXER_SHAREDPTR_H_INCLUDED */