侵入式智能指针 boost::instrusive
Link Share :https://zhiqiang.org/coding/boost-instrusive-ptr.html
- via RSS
如果理解了侵入式容器,侵入式智能指针也很容易理解。传统的智能指针std::shared_ptr
使用了和数据无关的引用计数,这带来两个问题:
- 引用计数要在
shared_ptr
对象间共享,所以它只能位于堆上。这使得每次都需要重新new
一小块内存。这导致性能问题。 - 引用计数的内存区域和数据区域不一致,缓存失效导致性能问题。
编写代码不善,将导致同一个数据,绑定到了两个引用计数,从而导致双重删除问题。典型代码如下:
int* x = new int; std::sharedptr
x1 = x; std::shared ptrx2 = x;
侵入式智能指针试图解决这些问题,方法也特别直接,那就是将引用计数直接塞进数据本身,和数据共存亡。从用户角度,这只需要继承boost::instrusive_ptr_base
基类:
struct T : public boost::instrusive_ptr_base<T>
{
public:
int age;
std::string name;
};
T* t = new T();
// 下面这么些很安全,而且速度很快!
boost::instrusive_ptr<T> x1 =t;
boost::instrusive_ptr<T> x2 =t;
我们看boost::instrusive_ptr_base
的定义,其核心就是增加一个原子操作的引用计数,以及自增和自减引用计数的函数:
template<class T>
class boost::intrusive_ptr_base {
public:
intrusive_ptr_base() : ref_count(0) {}
friend void intrusive_ptr_add_ref(intrusive_ptr_base<T> const* p) {
++p->ref_count;
}
friend void intrusive_ptr_release(intrusive_ptr_base<T> const* p) {
if (--p->ref_count == 0) {
boost::checked_delete(static_cast<T const*>(s));
}
}
boost::intrusive_ptr<T> self() {
return boost::intrusive_ptr<T>((T*)this);
}
private:
mutable boost::detail::atomic_count ref_count;
};
接下来实际的boost::instrusive_ptr
的定义就很简单了:
template<class T>
class boost::intrusive_ptr {
public:
intrusive_ptr(T* p, bool add_ref = true) : px(p) {
if (px != 0 && add_ref) {
intrusive_ptr_add_ref(px);
}
}
~intrusive_ptr() {
if (px != 0) {
intrusive_ptr_release(px);
}
}
private:
T * px;
}
由于解决了std::shared_ptr
的三个问题,boost::instrusive_ptr
的效率更高。但它也有缺陷。除了侵入式设计之外,最重要的是boost::instrusive_ptr
无法支持weak_ptr
,从而无法解决环形引用问题。这时因为std::shared_ptr
里的数据对象和计数器分离,可以有不同的生命周期。shared_ptr
的引用计数里有两个计数对象,从而支持weak_ptr
。
另外一个方面,std::shared_ptr
也意识到了其性能问题,内部也提供机制解决这些问题,其核心便是std::make_shared
和std::enable_shared_from_this
。
参考:C++智能指针 3 :内存布局(非侵入式、enablesharedfrom_this & 侵入式)
作者暂无likerid, 赞赏暂由本网站代持,当作者有likerid后会全部转账给作者(我们会尽力而为)。Tips: Until now, everytime you want to store your article, we will help you store it in Filecoin network. In the future, you can store it in Filecoin network using your own filecoin.
Support author:
Author's Filecoin address:
Or you can use Likecoin to support author: