boost::intrusive_ptr一种“侵入式”的引用计数指针,它实际并不提供引用计数功能,而是要求被存储的对象自己实现引用计数功能,并提供intrusive_ptr_add_ref和intrusive_ptr_release函数接口供boost::intrusive_ptr调用。

下面通过一个具体的例子来说明boost::intrusive_ptr的用法,首先实现一个基类intrusive_ptr_base,定义intrusive_ptr_add_ref和intrusive_ptr_release函数来提供引用计数功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
* intrusive_ptr_base基类,提供intrusive_ptr_add_ref()和intrusive_ptr_release()函数来提供引用计数功能;
* 使用boost::intrusive_ptr指针存储的用户类类型必须继承自intrusive_ptr_base基类。
*/
#include <ostream>
#include <boost/checked_delete.hpp>
#include <boost/detail/atomic_count.hpp>
 
 
template<class T>
class intrusive_ptr_base {
public:
    /**
    * 缺省构造函数
    */
    intrusive_ptr_base(): ref_count(0) {
        std::cout << "  Default constructor " << std::endl;
    }
     
    /**
    * 不允许拷贝构造,只能使用intrusive_ptr来构造另一个intrusive_ptr
    */
    intrusive_ptr_base(intrusive_ptr_base<T> const&): ref_count(0) {
        std::cout << "  Copy constructor..." << std::endl;
    }
     
    /**
    * 不允许进行赋值操作
    */
    intrusive_ptr_base& operator=(intrusive_ptr_base const& rhs) {
        std::cout << "  Assignment operator..." << std::endl;
        return *this;
    }
     
    /**
    * 递增引用计数(放到基类中以便compiler能找到,否则需要放到boost名字空间中)
    */
    friend void intrusive_ptr_add_ref(intrusive_ptr_base<T> const* s) {
        std::cout << "  intrusive_ptr_add_ref..." << std::endl;
        assert(s->ref_count >= 0);
        assert(s != 0);
        ++s->ref_count;
    }
 
    /**
    * 递减引用计数
    */
    friend void intrusive_ptr_release(intrusive_ptr_base<T> const* s) {
        std::cout << "  intrusive_ptr_release..." << std::endl;
        assert(s->ref_count > 0);
        assert(s != 0);
        if (--s->ref_count == 0)
            boost::checked_delete(static_cast<T const*>(s));  //s的实际类型就是T,intrusive_ptr_base<T>为基类
    }
     
    /**
    * 类似于shared_from_this()函数
    */
    boost::intrusive_ptr<T> self() {
        return boost::intrusive_ptr<T>((T*)this);
    }
     
    boost::intrusive_ptr<const T> self() const {
        return boost::intrusive_ptr<const T>((T const*)this);
    }
     
    int refcount() const {
        return ref_count;
    }
     
private:
    ///should be modifiable even from const intrusive_ptr objects
    mutable boost::detail::atomic_count ref_count;
 
};

用户类类型需要继承intrusive_ptr_base基类,以便具有引用计数功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <string>
#include <boost/intrusive_ptr.hpp>
#include "intrusive_ptr_base.hpp"
 
/**
* 用户类类型继承自intrusive_ptr_base,该实现方式类似于boost::enable_shared_from_this<Y>
*/
class Connection : public intrusive_ptr_base< Connection > {
public:
    /**
    * 构造函数,调用intrusive_ptr_base< Connection >的缺省构造函数来初始化对象的基类部分
    */
    Connection(int id, std::string tag):
        connection_id( id ), connection_tag( tag ) {}
 
    /**
    * 拷贝构造函数,只复制自身数据,不能复制引用计数部分
    */
    Connection(const Connection& rhs):
        connection_id( rhs.connection_id ), connection_tag( rhs.connection_tag) {}
     
    /**
    * 赋值操作,同样不能复制引用计数部分
    */
    const Connection operator=( const Connection& rhs) {
        if (this != &rhs) {
            connection_id = rhs.connection_id;
            connection_tag = rhs.connection_tag;
        }
         
        return *this;
    }
 
private:
    int connection_id;
    std::string connection_tag;
};
 
int main() {
    std::cout << "Create an intrusive ptr" << std::endl;
    boost::intrusive_ptr< Connection > con0 (new Connection(4, "sss") );  //调用intrusive_ptr_add_ref()递增引用计数
    std::cout << "Create an intrusive ptr. Refcount = " << con0->refcount() << std::endl;
 
    boost::intrusive_ptr< Connection > con1 (con0);   //调用intrusive_ptr_add_ref()
    std::cout << "Create an intrusive ptr. Refcount = " << con1->refcount() << std::endl;
    boost::intrusive_ptr< Connection > con2 = con0;   //调用intrusive_ptr_add_ref()
    std::cout << "Create an intrusive ptr. Refcount = " << con2->refcount() << std::endl;
     
    std::cout << "Destroy an intrusive ptr" << std::endl;
 
    return 0;
}

程序运行输出:

Create an intrusive ptr
  Default constructor 
  intrusive_ptr_add_ref...
Create an intrusive ptr. Refcount = 1
  intrusive_ptr_add_ref...
Create an intrusive ptr. Refcount = 2
  intrusive_ptr_add_ref...
Create an intrusive ptr. Refcount = 3
Destroy an intrusive ptr
  intrusive_ptr_release...
  intrusive_ptr_release...
  intrusive_ptr_release...

对比boost::shared_ptr

使用boost::shared_ptr用户类本省不需要具有引用计数功能,而是由boost::shared_ptr来提供;使用boost::shared_ptr的一大陷阱就是用一个raw pointer多次创建boost::shared_ptr,这将导致该raw pointer被多次销毁当boost::shared_ptr析构时。即不能如下使用:

  int *a = new int(5);
  boost::shared_ptr ptr1(a);
  boost::shared_ptr ptr2(a);  //错误! 
 
 
boost::intrusive_ptr完全具备boost::shared_ptr的功能,且不存在shared_ptr的问题,即可以利用raw pointer创建多个intrusive _ptr,其原因就在于引用计数的ref_count对象,shared_ptr是放在shared_ptr结构里,而目标对象T通过继承intrusive_ptr_base将引用计数作为T对象的内部成员变量,就不会出现同一个对象有两个引用计数器的情况出现。
 

那么为什么通常鼓励大家使用shared_ptr,而不是intrusive_ptr呢, 在于shared_ptr不是侵入性的,可以指向任意类型的对象; 而intrusive_ptr所要指向的对象,需要继承intrusive_ptr_base,即使不需要,引用计数成员也会被创建。

结论:如果创建新类且需要进行传递,则继承intrusive_ptr_base,使用intrusive_ptr。

boost::intrusive_ptr原理介绍的更多相关文章

  1. 03 Yarn 原理介绍

    Yarn 原理介绍 大纲: Hadoop 架构介绍 YARN 产生的背景 YARN 基础架构及原理   Hadoop的1.X架构的介绍   在1.x中的NameNodes只可能有一个,虽然可以通过Se ...

  2. 04 MapReduce原理介绍

    大数据实战(上) # MapReduce原理介绍 大纲: * Mapreduce介绍 * MapReduce2运行原理 * shuffle及排序    定义 * Mapreduce 最早是由googl ...

  3. Android Animation学习(一) Property Animation原理介绍和API简介

    Android Animation学习(一) Property Animation介绍 Android Animation Android framework提供了两种动画系统: property a ...

  4. [转]MySQL主从复制原理介绍

    MySQL主从复制原理介绍 一.复制的原理 MySQL 复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新.删除等等).每个从服务器从主服务器接收主服务器已经记录到其二进制日志的保存的更新,以 ...

  5. 分布式文件系统FastDFS原理介绍

    在生产中我们一般希望文件系统能帮我们解决以下问题,如:1.超大数据存储:2.数据高可用(冗余备份):3.读/写高性能:4.海量数据计算.最好还得支持多平台多语言,支持高并发. 由于单台服务器无法满足以 ...

  6. 内存分析_.Net内存原理介绍

    内存原理介绍 1.       .Net应用程序中的内存 1.1.Net内存类型 Windows使用一个系统:虚拟寻址系统.这个系统的作用是将程序可用的内存地址映射到硬件内存中的实际地址上.其实际结果 ...

  7. 液晶常用接口“LVDS、TTL、RSDS、TMDS”技术原理介绍

    液晶常用接口“LVDS.TTL.RSDS.TMDS”技术原理介绍 1:Lvds Low-Voltage Differential Signaling 低压差分信号 1994年由美国国家半导体公司提出之 ...

  8. 淘宝JAVA中间件Diamond详解(2)-原理介绍

    淘宝JAVA中间件Diamond详解(二)---原理介绍 大家好,通过第一篇的快速使用,大家已经对diamond有了一个基本的了解.本次为大家带来的是diamond核心原理的介绍,主要包括server ...

  9. Traceroute原理介绍

    一.路由追踪 路由跟踪,就是获取从主机A到达目标主机B这个过程中所有需要经过的路由设备的转发接口IP. 二.ICMP协议 Internet控制报文协议(internet control message ...

随机推荐

  1. jquery colsest的用法

    如果有class,就是他自己,没有就在父级去找 e=e||window.event; var target=e.srcElement?e.srcElement:e.target; var parent ...

  2. 在页面中嵌入svg的几种方法

    //在页面中嵌入svg的方法1:使用 <embed> 标签<embed> 标签被所有主流的浏览器支持,并允许使用脚本.注释:当在 HTML 页面中嵌入 SVG 时使用 < ...

  3. 进入保护模式(二)——《x86汇编语言:从实模式到保护模式》读书笔记14

    首先来段题外话:之前我发现我贴出的代码都没有行号,给讲解带来不便.所以从现在起,我要给代码加上行号.我写博客用的这个插入代码的插件,确实不支持自动插入行号.我真的没有找到什么好方法,无奈之下,只能按照 ...

  4. Java Service Wrapper 发布Java程序或者jar包为Windows服务

    下载Windows版本:http://nchc.dl.sourceforge.net/sourceforge/wrapper/wrapper-windows-x86-32-3.2.3.zip 现在目前 ...

  5. CentOS7 防火墙操作

    1.firewalld的基本使用 启动: systemctl start firewalld 关闭: systemctl stop firewalld 查看状态: systemctl status f ...

  6. Hibernate一对多关系操作

    1.创建两个实体类. 一个实体类是商品类,另一个实体类是商品的分类类. 在一对多关系的两个实体中,在编写实体类时必须要遵循以下规则: (1)在一的那一方的实体中,必须要有一个私有的多那一方的实体对象属 ...

  7. 使用YUM安装MySQL 5.5(适用于CentOS6.2/5.8及Fedora 17/16平台)

    目前CentOS/Red Hat (RHEL) 6.2官方自带的mysql版本为5.1,mysql5.5已经出来了. 相比mysql5.1,mysql5.5不仅在多个方面进行了改进: 性能上有了很大提 ...

  8. bitbucket 源代码托管

    5个人以下可以免费使用,不限制仓库的数量; 国外的注册需要开启蓝灯FQ; 1.注册账号 maanshancss w1-g1@qq.com;创建仓库; 然后拷贝现有项目 然后提交 然后push; 2.写 ...

  9. 我的Chrome插件---纪录

    1.极简图床 写博客的时候用的上. 2.谷歌翻译 阅读英文文档直接选中翻译 3.OneTab 把当前网页集成一个tab,它有个好处就是,在写博客的时候,需要上不同的网站,写了一半有其他的事,这是可以集 ...

  10. C#学习笔记14

    1.在多个线程的同步数据中,避免使用this.typeof(type).string进行同步锁,使用这3个容易造成死锁. 2.使用Interlocked类:我们一般使用的互斥锁定模式(同步数据)为Lo ...