In principle, you are right. Your example will cause the pointer to freeze (note that there are some exceptions if you use boost::enable_shared_from_this as the base class).
Description
Problem
boost:shared_ptr and std::shared_ptr use the same idea: create a smart pointer with a reference count from the raw pointer. However, they also share the same problem as all smart pointers: if you use a raw pointer in another smart pointer that is not associated with your other smart pointer, you end up dangling pointers and a few delete calls:
int * ptr = new int; { std::shared_ptr<int> shared1(ptr);
"Decision"
After creating your first smart pointer S from the raw pointer p to the O object, you should only use copy constructors with S , not p if O isnβt derived from std::enable_shared_from_this . boost has a somewhat equivalent to this, but mixing the source pointer and smart pointer is still bad. Even better - do not use raw pointer if you are working with a smart pointer:
std::shared_ptr<int> ptr(new int); { std::shared_ptr<int> shared1(ptr);
Even better, do not allocate memory yourself, but use std::make_shared or boost:make_shared :
std::shared_ptr<int> ptr = std::make_shared<int>(); { std::shared_ptr<int> shared1(ptr);
Possible implementation
The following implementation is very crude compared to std::shared_ptr , because it does not support std::weak_ptr and std::enable_shared_from_this . However, it should give you an overview of how to handle a generic pointer:
//!\brief Base clase for reference counter class reference_base{ reference_base(const reference_base&); // not copyable reference_base& operator=(const reference_base &){return *this;}// not assignable protected: size_t ref_count; //!< reference counter virtual void dispose() = 0; //!< pure virtual public: //! initialize with a single reference count reference_base() : ref_count(1){} //! returns the current count of references size_t use_count() const{ return ref_count; } //! increases the current count of references void increase(){ ref_count++; } //! decreases the current count of references and dispose if the counter drops to zero void decrease(){ if(--ref_count == 0) dispose(); } }; //! \brief Specialized version for pointer template <class T> class reference_base_ptr : public reference_base{ typedef T* pointer_type; protected: //! uses delete to deallocate memory virtual void dispose(){ delete ptr; ptr = 0; } public: reference_base_ptr(T * ptr) : ptr(ptr){} pointer_type ptr; }; //! \brief Specialized version for arrays template <class T> class reference_base_range : public reference_base{ typedef T* pointer_type; protected: virtual void dispose(){ delete[] ptr; ptr = 0; } public: reference_base_range(T * ptr) : ptr(ptr){} pointer_type ptr; }; /***********************************************************/ //! base class for shared memory template <class T, class reference_base_type> class shared_memory{ public: typedef T element_type; //! Standard constructor, points to null shared_memory() : reference_counter(new reference_base_type(0)){} //! Constructs the shared_memroy and creates a new reference_base template<class Y> shared_memory(Y * ptr){ try{ reference_counter = new reference_base_type(ptr); }catch(std::bad_alloc &e){ delete ptr; throw; } } //! Copies the shared_memory and increases the reference count shared_memory(const shared_memory & o) throw() : reference_counter(o.reference_counter){ o.reference_counter->increase(); } //! Copies the shared_memory of another pointer type and increases the reference count. //! Needs the same reference_base_type template<class Y> shared_memory(const shared_memory<Y,reference_base_type> & o) throw() : reference_counter(o.reference_counter){ reference_counter->increase(); } //! Destroys the shared_memory object and deletes the reference_counter if this was the last //! reference. ~shared_memory(){ reference_counter->decrease(); if(reference_counter->use_count() == 0) delete reference_counter; } //! Returns the number of references size_t use_count() const{ return reference_counter->use_count(); } //! Returns a pointer to the refered memory T * get() const{ return reference_counter->ptr; } //! Checks whether this object is unique bool unique() const{ return use_count() == 1; } //! Checks whehter this object is valid operator bool() const{ return get() != 0; } //! Checks doesn't reference anythign bool empty() const{ return get() == 0; } //! Assignment operator for derived classes template<class Y> shared_memory& operator=(const shared_memory<Y,reference_base_type> & o){ shared_memory<Y,reference_base_type> tmp(o); swap(tmp); } //! Assignment operator shared_memory& operator=(const shared_memory & o){ shared_memory tmp(o); swap(tmp); return *this; } /** resets the ptr to NULL. If this was the last shared_memory object * owning the referenced object, the object gets deleted. * \sa ~shared_memory */ void reset(){ shared_memory tmp; swap(tmp); } /** releases the old object and takes a new one */ template <class Y> void reset(Y * ptr){ shared_memory tmp(ptr); swap(tmp); } /** swaps the owned objects of two shared_memory objects. */ void swap(shared_memory & r){ reference_base_type * tmp = reference_counter; reference_counter = r.reference_counter; r.reference_counter = tmp; } protected: reference_base_type * reference_counter; //!< Actually reference counter and raw pointer }; /***********************************************************/ //! ptr (single object) specialization template <class T> class shared_ptr : public shared_memory<T,reference_base_ptr<T> >{ typedef reference_base_ptr<T> reference_counter_type; typedef shared_memory<T,reference_counter_type> super; typedef T element_type; public: shared_ptr(){} template<class Y> shared_ptr(Y * ptr){ try{ super::reference_counter = new reference_counter_type(ptr); }catch(std::bad_alloc &e){ //couldn't allocated memory for reference counter delete ptr; // prevent memory leak throw bad_alloc(); } } element_type & operator*() const{ return *(super::reference_counter->ptr); } element_type * operator->() const{ return super::reference_counter->ptr; } }; /***********************************************************/ //! array (range) specialization template <class T> class shared_array : public shared_memory<T,reference_base_range<T> >{ typedef reference_base_range<T> reference_counter_type; typedef shared_memory<T,reference_counter_type> super; typedef T element_type; public: shared_array(){} template<class Y> shared_array(Y * ptr){ try{ super::reference_counter = new reference_counter_type(ptr); }catch(std::bad_alloc &e){ delete[] ptr; throw bad_alloc(); } } element_type & operator[](int i) const{ return *(super::reference_counter->ptr + i); } };
See also: