zoukankan      html  css  js  c++  java
  • boost::intrusive_ptr原理介绍

    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。
  • 相关阅读:
    LinkedListQueue
    LinkedListStack
    redis学习之——Redis事务(transactions)
    redis学习之——持久化RDB 和AOF
    redis学习之——redis.conf配置(基本)文件学习
    评估算法的核心指标
    Vector类
    List接口与ArrayList、LinkedList实现类
    Collection接口
    枚举类
  • 原文地址:https://www.cnblogs.com/sunshinewave/p/5296806.html
Copyright © 2011-2022 走看看