/*! \file \brief BDM's own smart pointer. \author Vaclav Barta. ----------------------------------- BDM++ - C++ library for Bayesian Decision Making under Uncertainty Using IT++ for numerical operations ----------------------------------- */ #ifndef shared_ptr_h #define shared_ptr_h #include #include #include #include #include "itpp_ext.h" namespace bdm { //! A naive implementation of roughly a subset of the std::tr1:shared_ptr spec (really just roughly - it ignores memory exceptions, for example; also note I didn't read the spec). // The standard template would naturally be preferable, _if_ it was // included in the standard libraries of all supported compilers - but // that's exactly what remains to be seen... template class shared_ptr { template friend class shared_ptr; private: T *payload; unsigned *refCnt; public: //! Creates an empty shared_ptr - one that doesn't point anywhere. shared_ptr(): payload(0), refCnt(0) { } //! Constructs a shared_ptr that owns the pointer p (unless p is //! null, in which case this constructor creates an empty //! shared_ptr). shared_ptr(T *p): payload(p), refCnt(p ? new unsigned(1) : 0) { } //! If other is empty, constructs an empty shared_ptr; otherwise, //! constructs a shared_ptr that shares ownership with other. shared_ptr(const shared_ptr &other): payload(other.payload), refCnt(other.refCnt) { add_ref(); } //! If other is empty, constructs an empty shared_ptr; otherwise, //! constructs a shared_ptr that shares ownership with other. template shared_ptr(const shared_ptr &other): payload(other.payload), refCnt(other.refCnt) { add_ref(); } ~shared_ptr() { del_ref(); } shared_ptr &operator=(const shared_ptr &other) { other.add_ref(); del_ref(); payload = other.payload; refCnt = other.refCnt; return *this; } //! Returns the stored pointer (which remains owned by this //! instance). T *get() { return payload; } //! Returns the stored pointer (which remains owned by this //! instance). This method may only be called when the stored //! pointer isn't NULL. T *operator->() { it_assert_debug(payload, "dereferencing NULL"); return payload; } //! Returns a reference to the object pointed to by the stored //! pointer. This method may only be called when the stored pointer //! isn't NULL. T &operator*() { it_assert_debug(payload, "dereferencing NULL"); return *payload; } //! Returns the stored pointer (which remains owned by this //! instance). const T* get() const { return payload; } //! Returns the stored pointer (which remains owned by this //! instance). This method may only be called when the stored //! pointer isn't NULL. const T *operator->() const { it_assert_debug(payload, "dereferencing NULL"); return payload; } //! Returns a reference to the object pointed to by the stored //! pointer. This method may only be called when the stored pointer //! isn't NULL. const T &operator*() const { it_assert_debug(payload, "dereferencing NULL"); return *payload; } bool unique() const { return refCnt && (*refCnt == 1); } long use_count() const { return refCnt ? *refCnt : 0; } operator bool() const { return payload; } void swap(shared_ptr &other) { std::swap(payload, other.payload); std::swap(refCnt, other.refCnt); } private: void add_ref() const { if (refCnt) { if (*refCnt == UINT_MAX) { throw std::overflow_error( std::string("Shared pointer has too many references.")); } ++*refCnt; } } void del_ref() { if (refCnt) { if (!(--*refCnt)) { delete payload; delete refCnt; } } } }; template bool operator==(shared_ptr const &a, shared_ptr const &b) { return a.get() == b.get(); } template bool operator!=(shared_ptr const &a, shared_ptr const &b) { return a.get() != b.get(); } template bool operator<(shared_ptr const &a, shared_ptr const &b) { return a.get() < b.get(); } } #endif