gpt4 book ai didi

c++ - boost shared_ptr的底层设计

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:30:39 26 4
gpt4 key购买 nike

我想了解 boost shared_ptr 类的底层设计。我想将它“移植”到 fortran(不要问)。我理解的一件事是引用计数由 shared_count 类持有。这提示了我一个问题。很久没用过C++了,也没用过boost。

假设我分配了一个类 X 的实例,然后将它传递给两个不同的 shared_ptr 实例。据我了解,每个 shared_ptr 实例对另一个实例一无所知,因此两个 shared_ptr 实例都引用同一个 X 实例,同时保持引用计数为 1。如果一个 shared_ptr 超出范围而另一个不超出范围,则X 对象将被删除(因为引用计数降为零)并且剩余的 shared_ptr 将有一个悬空指针。为了保持 shared_ptr 引用计数,您必须从另一个 shared_ptr 创建一个 shared_ptr。

我说得对吗?如果不是,boost 如何跟踪哪些 shared_ptrs 正在引用一个对通过 shared_ptrs 引用的事实一无所知的类?

最佳答案

基本上你是对的。您的示例将导致悬垂指针(请注意,如果您使用 boost::enable_shared_from_this 作为基类,则有一些异常(exception))。

解释

问题

boost:shared_ptrstd::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

“解决方案”

在你从原始指针 p 到对象 O 创建了你的第一个智能指针 S 之后,你应该只使用复制构造函数 S,而不是 p,只要 O 不是 std::enable_shared_from_this 的派生词. boost 有点等同于此,但混合原始指针和智能指针仍然是一个坏主意。更好的是 - 如果您使用智能指针,请不要使用原始指针:

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_sharedboost: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_ptrstd::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);
}
};

另见:

关于c++ - boost shared_ptr的底层设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11669269/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com