欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C++侵入式智能指针的实现

程序员文章站 2022-11-21 19:51:15
简介 在现代c++中,智能指针给我们在资源管理上带来了很多好处,这里就不多说了。 在工作中,我们常常会用智能指针来管理资源,其中最常用的就是引用计数类智能指针了(shared_ptr)。 资源共享型...

简介

在现代c++中,智能指针给我们在资源管理上带来了很多好处,这里就不多说了。

在工作中,我们常常会用智能指针来管理资源,其中最常用的就是引用计数类智能指针了(shared_ptr)。

资源共享型的智能指针有两种实现,一种是侵入式,一种是非侵入式。

在教材里比较常见的是非侵入式的,它的实现完全放在智能指针模板里,模板类有一个用于保存资源类对象的指针变量,和一个用于记录资源对象使用计数的指针变量,这两个东西是所有的智能指针对象共享的,所以通过指针保存。

C++侵入式智能指针的实现

而侵入式则不同,它的实现分散在智能指针模板和使用智能指针模板的类中:模板类只有一个用于保存对象的指针变量,对象的计数放在了资源类中。

C++侵入式智能指针的实现vc+436osyrntw8tatobssrhivc/j2aos0rkxyl3pslliq6o7pc9wpg0kpha+mqgi0vloqtl908o8xsr9toa0ottatttp87g+ye2jrmv50ttu2rqvyv2199pdtctksbryv8ns1naxvdo0q7xd18rutlbuz/o12na3o6y2+lk708o1o9de0v3tw7zgyv3wtbaqyqejqlfhx9bi68q91sfe3na41eu21m/ztcs/vbg0o6yx2ndrtpjxxdbhxnzwunxrxkow5aost/hu8r7nu+gz9s/wtttp89l908o8xsr9tqrkp6opoam8l3a+dqo8cd7isbxjysejujwvcd4ncjxwpjghotfk1lta4lhy0ovt0nl908o8xsr9setbv6ossqlh0rjdsetbv7xe1pa89b/j0tsxu8fwyovkvdbhxnzwunxrxkow5bv5wocy2df3o6zv4s/utcpc6bezo7s8l3a+dqo8cd4yoali57n7umpa4lkisrvp68q508pwx8tc1rjv66osy/y7ucrhu+g0+nff0v3tw7zgyv2x5mg/oam8l3a+dqo8cd7b7c3io6zwx8tc1rjv69pq0ru49s7et6ix3mpitctoyszio6y+zcrh0a27t9l908ohozwvcd4ncjxomibpzd0="侵入式智能指针实现">侵入式智能指针实现

两个要点:

1.将引用计数变量从资源类中抽离出来,封装成一个基类,该基类包含了引用计数变量。如果一个类想使用智能指针,则只需要继承自该基类即可;

2.引用计数的基类,设计成模板类,接受引用计数类型作为参数,比如使用int类型或者原子计数类型作为引用计数变量。默认情况下应该使用原子计数类型作为引用计数变量。

3.引用计数基类的构造函数、拷贝构造函数、析构函数应为protected,即该类只能通过继承关系被使用。

4.拷贝构造函数并不拷贝引用计数基类的数据成员,而是重新将原子计数_atomic置为0——因为每个对象都有一个自己的引用计数,当发生对象拷贝构造时,新的对象的计数应该置为0,而不应该拷贝旧对象的计数。

5.赋值操作operator=,比如a=b,同上面一样,只对资源类的成员进行拷贝,而不拷贝其引用计数基类的数据成员。也就是说,将b的值赋给a,a的引用计数应该保持不变,而不能将b的引用计数拷贝过来——这是对象的拷贝,而不是智能指针的拷贝。

首先实现引用计数基类(注:atomic的实现这里就不给出了):

/**
 *  @brief 智能指针基类.
 *  
 *  所有需要智能指针支持的类都需要从该对象继承,
 *  
 *  内部采用引用计数atomic实现,对象可以放在容器中;
 */

template
class handlebaset
{
public:

     /** 原子计数类型*/
    typedef t atomic_type;

    /**
     * @brief 复制。引用计数不能被复制。
     *
     * @return handlebase&
     */
    handlebaset& operator=(const handlebaset&)
    {
        return *this;
    }

    /**
     * @brief 增加计数
     */
    void incref() { _atomic.inc_fast(); }

    /**
     * @brief 减少计数, 当计数==0时, 且需要删除数据时, 释放对象
     */
    void decref()
    {
        if(_atomic.dec_and_test() && !_bnodelete)
        {
            _bnodelete = true;
            delete this;
        }
    }

    /**
     * @brief 获取计数.
     *
     * @return int 计数值
     */
    int getref() const        { return _atomic.get(); }

    /**
     * @brief 设置不自动释放. 
     *  
     * @param b 是否自动删除,true or false
     */
    void setnodelete(bool b)  { _bnodelete = b; }

protected:

    /**
     * @brief 构造函数
     */
    handlebaset() : _atomic(0), _bnodelete(false)
    {
    }

    /**
     * @brief 拷贝构造,_atomic和_bnodelete不能被拷贝,只能重置
     */
    handlebaset(const handlebaset&) : _atomic(0), _bnodelete(false)
    {
    }

    /**
     * @brief 析构
     */
    virtual ~handlebaset()
    {
    }

protected:

    /**
     * 计数
     */
    atomic_type   _atomic;

    /**
     * 是否自动删除
     */
    bool        _bnodelete;
};

// 针对int类型计数变量的特化
// 在类声明中定义的函数将自动inline,类外定义的函数需显式inline
template<>
inline void handlebaset::incref() 
{ 
    ++_atomic; 
}

template<> 
inline void handlebaset::decref()
{
    if(--_atomic == 0 && !_bnodelete)
    {
        _bnodelete = true;
        delete this;
    }
}

template<> 
inline int handlebaset::getref() const        
{ 
    return _atomic; 
} 

// 默认使用atomic作为引用计数类型
typedef handlebaset handlebase;

以上实现了计数基类,所有需要使用智能指针的对象必须继承自该类。

智能指针模板类的实现需要关注的几个点:

1.初始化、赋值等操作需要考虑参数是原始指针、其他类型的智能指针初、用同一类型的智能指针三种情况。

2.需要重载<、=、!=几个操作(非成员函数),左右操作数使用两个模板参数。

3.赋值操作需要检查自我赋值。

/**
* @brief 空指针异常
*/
struct shared_ptrnull_exception : public exception
{
    shared_ptrnull_exception(const string &buffer) : exception(buffer){};
    ~shared_ptrnull_exception() throw(){};
};

/**
 * @brief 智能指针模板类. 
 *  
 * 可以放在容器中,且线程安全的智能指针. 
 *  
 * 通过它定义智能指针,该智能指针通过引用计数实现, 
 *  
 * 可以放在容器中传递. 
 *  
 * template t必须继承于handlebase 
 */
template
class shared_ptr
{
public:

    /**
     * 元素类型
     */
    typedef t element_type;

    /**
     * @brief 用原生指针初始化, 计数+1. 
     *  
     * @param p
     */
    shared_ptr(t* p = 0)
    {
        _ptr = p;

        if(_ptr)
        {
            _ptr->incref();
        }
    }

    /**
     * @brief 用其他智能指针r的原生指针初始化, 计数+1. 
     *  
     * @param y
     * @param r
     */
    template
    shared_ptr(const shared_ptr& r)
    {
        _ptr = r._ptr;

        if(_ptr)
        {
            _ptr->incref();
        }
    }

    /**
     * @brief 拷贝构造, 计数+1. 
     *  
     * @param r
     */
    shared_ptr(const shared_ptr& r)
    {
        _ptr = r._ptr;

        if(_ptr)
        {
            _ptr->incref();
        }
    }

    /**
     * @brief 析构
     */
    ~shared_ptr()
    {
        if(_ptr)
        {
            _ptr->decref();
        }
    }

    /**
     * @brief 赋值, 普通指针. 
     *  
     * @param p 
     * @return shared_ptr&
     */
    shared_ptr& operator=(t* p)
    {
        if(_ptr != p)
        {
            if(p)
            {
                p->incref();
            }

            t* ptr = _ptr;
            _ptr = p;

            if(ptr)
            {
                ptr->decref();
            }
        }
        return *this;
    }

    /**
     * @brief 赋值, 其他类型智能指针. 
     *  
     * @param y
     * @param r 
     * @return shared_ptr&
     */
    template
    shared_ptr& operator=(const shared_ptr& r)
    {
        if(_ptr != r._ptr)
        {
            if(r._ptr)
            {
                r._ptr->incref();
            }

            t* ptr = _ptr;
            _ptr = r._ptr;

            if(ptr)
            {
                ptr->decref();
            }
        }
        return *this;
    }

    /**
     * @brief 赋值, 该类型其他执政指针. 
     *  
     * @param r 
     * @return shared_ptr&
     */
    shared_ptr& operator=(const shared_ptr& r)
    {
        if(_ptr != r._ptr)
        {
            if(r._ptr)
            {
                r._ptr->incref();
            }

            t* ptr = _ptr;
            _ptr = r._ptr;

            if(ptr)
            {
                ptr->decref();
            }
        }
        return *this;
    }

    /**
     * @brief 将其他类型的智能指针换成当前类型的智能指针. 
     *  
     * @param y
     * @param r 
     * @return shared_ptr
     */
    template
    static shared_ptr dynamiccast(const shared_ptr& r)
    {
        return shared_ptr(dynamic_cast(r._ptr));
    }

    /**
     * @brief 将其他原生类型的指针转换成当前类型的智能指针. 
     *  
     * @param y
     * @param p 
     * @return shared_ptr
     */
    template
    static shared_ptr dynamiccast(y* p)
    {
        return shared_ptr(dynamic_cast(p));
    }

    /**
     * @brief 获取原生指针.
     *
     * @return t*
     */
    t* get() const
    {
        return _ptr;
    }

    /**
     * @brief 调用.
     *
     * @return t*
     */
    t* operator->() const
    {
        if(!_ptr)
        {
            thrownullhandleexception();
        }

        return _ptr;
    }

    /**
     * @brief 引用.
     *
     * @return t&
     */
    t& operator*() const
    {
        if(!_ptr)
        {
            thrownullhandleexception();
        }

        return *_ptr;
    }

    /**
     * @brief 是否有效.
     *
     * @return bool
     */
    operator bool() const
    {
        return _ptr ? true : false;
    }

    /**
     * @brief  交换指针. 
     *  
     * @param other
     */
    void swap(shared_ptr& other)
    {
        std::swap(_ptr, other._ptr);
    }

protected:

    /**
     * @brief 抛出异常
     */
    void thrownullhandleexception() const;

public:
    t*          _ptr;

};

/**
 * @brief 抛出异常. 
 *  
 * @param t
 * @param file
 * @param line
 */
template inline void
shared_ptr::thrownullhandleexception() const
{
    throw shared_ptrnull_exception("shared_ptr null handle error");
}

/**
 * @brief ==判断. 
 *  
 * @param t
 * @param u
 * @param lhs
 * @param rhs
 *
 * @return bool
 */
template
inline bool operator==(const shared_ptr& lhs, const shared_ptr& rhs)
{
    t* l = lhs.get();
    u* r = rhs.get();
    if(l && r)
    {
        return *l == *r;
    }
    else
    {
        return !l && !r;
    }
}

/**
 * @brief 不等于判断. 
 *  
 * @param t
 * @param u
 * @param lhs
 * @param rhs
 *
 * @return bool
 */
template
inline bool operator!=(const shared_ptr& lhs, const shared_ptr& rhs)
{
    t* l = lhs.get();
    u* r = rhs.get();
    if(l && r)
    {
        return *l != *r;
    }
    else
    {
        return l || r;
    }
}

/**
 * @brief 小于判断, 用于放在map等容器中. 
 *  
 * @param t
 * @param u
 * @param lhs
 * @param rhs
 *
 * @return bool
 */
template
inline bool operator<(const shared_ptr& lhs, const shared_ptr& rhs)
{
    t* l = lhs.get();
    u* r = rhs.get();
    if(l && r)
    {
        return *l < *r;
    }
    else
    {
        return !l && r;
    }
}

使用示例

class test: public handlebase
{
    // ...
};

shared_ptr mytestclass = new test();