基本上你是对的。您的示例将导致悬空指针(请注意,如果您boost::enable_shared_from_this
用作基类,则会出现一些例外情况)。
解释
问题
boost:shared_ptr
并std::shared_ptr
分享相同的想法:使用原始指针的引用计数创建一个智能指针。但是,它们也存在所有智能指针所具有的相同问题:如果您在另一个与您的其他智能指针无关的智能指针中使用原始指针,您将以悬空指针和多次调用结束delete
:
int * ptr = new int;
{
std::shared_ptr<int> shared1(ptr); // initialise a new ref_count = 1
{
std::shared_ptr<int> shared2(ptr); // initialise a new ref_count = 1
} // first call of delete, since shared2.use_count() == 0
} // second call of delete, since shared1.use_count() == 0. ooops
“解决方案”
从指向对象的S
原始指针创建第一个智能指针后,只要不是从. boost 有点等价于这个,但是混合原始指针和智能指针仍然是一个坏主意。更好的是 - 如果您使用智能指针,请不要使用原始指针:p
O
S
p
O
std::enable_shared_from_this
std::shared_ptr<int> ptr(new int);
{
std::shared_ptr<int> shared1(ptr); // ptr.use_count() == 2
{
std::shared_ptr<int> shared2(ptr); // ptr.use_count() = 3
} // ptr.use_count() = 2
} // ptr.use_count() = 1
更好的是,不要自己分配内存,而是使用std::make_shared
or boost:make_shared
:
std::shared_ptr<int> ptr = std::make_shared<int>();
{
std::shared_ptr<int> shared1(ptr); // ptr.use_count() == 2
{
std::shared_ptr<int> shared2(ptr); // ptr.use_count() == 3
} // ptr.use_count() == 2
} // ptr.use_count() == 1
可能的实施
与 相比,以下实现非常粗糙std::shared_ptr
,因为它不支持std::weak_ptr
和std::enable_shared_from_this
。但是,它应该为您提供如何处理共享指针的概述:
//!\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);
}
};
也可以看看: