#ifndef SAFE_PTR_HH #define SAFE_PTR_HH #include template class safe_ptr; namespace safe_ptr_impl { struct cell_t { void * datum; unsigned int rc; }; } template class safe_ptr { safe_ptr_impl::cell_t * cell; template friend class safe_ptr; public: safe_ptr() : cell(0) {} template explicit safe_ptr(U * datum) : cell(0) { (void)static_cast(static_cast(0)); if (datum != 0) { cell = new safe_ptr_impl::cell_t; cell->datum = datum; cell->rc = 1; } } explicit safe_ptr(T const & datum) : cell(new safe_ptr_impl::cell_t) { cell->datum = new T(datum); cell->rc = 1; } safe_ptr(safe_ptr const & rc) : cell(rc.cell) { if (cell != 0) ++cell->rc; } template safe_ptr(safe_ptr const & rc) : cell(rc.cell) { (void)static_cast(static_cast(0)); if (cell != 0) ++cell->rc; } safe_ptr & operator = (safe_ptr const & rc) { safe_ptr tmp = rc; swap(tmp); return *this; } void swap(safe_ptr & other) throw () { safe_ptr_impl::cell_t * tmp = cell; cell = other.cell; other.cell = tmp; } T * release() { if (cell == 0) return 0; if (cell->rc > 1) { throw std::string("trying to release " "an aliased safe_ptr"); } T * datum = static_cast(cell->datum); delete cell; cell = 0; return datum; } void reset() { reset(0); } template void reset(U * datum) { safe_ptr tmp(datum); swap(tmp); } ~safe_ptr() { if (cell != 0 && --cell->rc == 0) { delete static_cast(cell->datum); delete cell; } } T * operator->() const throw (std::out_of_range) { if (cell == 0) throw std::out_of_range("null safe_ptr dereference"); return static_cast(cell->datum); } T & operator*() const throw (std::out_of_range) { if (cell == 0) throw std::out_of_range("null safe_ptr dereference"); return *static_cast(cell->datum); } }; #endif /* REFCOUNT_HH */