#ifndef REFPTR_H #define REFPTR_H REFPTR_H #include /* NULL */ #include /* std::atomic */ template class refptr { public: refptr(); refptr(T * ptr); refptr(const refptr & orig); refptr & operator=(const refptr & orig); refptr & operator=(T * ptr); ~refptr(); T & operator*() const; T * operator->() const; bool isNull() const { return m_ptr == NULL; } bool operator==(const refptr & right) const; bool operator!=(const refptr & right) const; private: void cloneFrom(const refptr & orig); void destroy(); T * m_ptr; /* reference count is atomic so that refptr copies may be made * concurrently from multiple threads (e.g. the multithreaded * renderer) without corrupting the count */ std::atomic * m_refCount; }; template refptr::refptr() { m_ptr = NULL; m_refCount = NULL; } template refptr::refptr(T * ptr) { m_ptr = ptr; m_refCount = new std::atomic(1); } template refptr::refptr(const refptr & orig) { cloneFrom(orig); } template refptr & refptr::operator=(const refptr & orig) { destroy(); cloneFrom(orig); return *this; } template refptr & refptr::operator=(T * ptr) { destroy(); m_ptr = ptr; m_refCount = new std::atomic(1); return *this; } template void refptr::cloneFrom(const refptr & orig) { this->m_ptr = orig.m_ptr; this->m_refCount = orig.m_refCount; if (m_refCount != NULL) m_refCount->fetch_add(1, std::memory_order_relaxed); } template refptr::~refptr() { destroy(); } template void refptr::destroy() { if (m_refCount != NULL) { /* fetch_sub returns the value prior to the decrement; if it was 1 * then this was the last reference and we own the cleanup */ if (m_refCount->fetch_sub(1, std::memory_order_acq_rel) == 1) { delete m_ptr; delete m_refCount; } } } template T & refptr::operator*() const { return *m_ptr; } template T * refptr::operator->() const { return m_ptr; } template bool refptr::operator==(const refptr & right) const { return m_ptr == right.m_ptr; } template bool refptr::operator!=(const refptr & right) const { return m_ptr != right.m_ptr; } #endif