当前位置: 移动技术网 > IT编程>开发语言>C/C++ > C++侵入式智能指针的实现

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

2019年01月06日  | 移动技术网IT编程  | 我要评论

翟煦飞,涿州灯会,净利润怎么算

简介

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

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

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

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

这里写图片描述

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

这里写图片描述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();

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网