智能指针

智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。——摘自百度百科
简单来说,就是当同一个对象有多个指针指向它本身时,需要记录指向对象本身的指针个数,而智能指针就是利用引用计数的方式在记录指针,算作对于指针而言的管理层,有效的管理指针所指向的动态资源的释放问题,避免产生创建指针却忘记释放指针,避免野指针的问题。
这里写图片描述
智能指针的发展历史
RAII,也称为“资源获取就是初始化”,是c++等编程语言常用的管理资源、避免内存泄露的方法。它保证在任何情况下,使用对象时先构造对象,最后析构对象。——摘自百度百科

RAII并不等价于智能指针,智能指针只是RAII思想的一种实现。

1、智能指针可以防止内存泄漏,利用shared_ptr来管理这类问题。
当shared_ptr管理的引用计数为0时,也就是最后一个指向对象的指针被删除时,就会自动的删除对象,防止程序再也找不到曾经管理的那个对象,从而防止内存泄漏。

template<typename T>
class shared_ptr
{
public:
    shared_ptr(T*p)
        , _count(new int(1))
        , _ptr(p)
    {}
    shared_ptr(shared_ptr<T>& p)
        , _ptr(p._ptr)
        , _count(&(++*p._count))
    {}
    T* operator->()
    {
        return _ptr;
    }
    T& operator*()
    {
        return *_ptr;
    }
    shared_ptr<T>& operator = (shared_ptr<T>& p)
    {
        ++*p._count;
        if (this->_ptr && (--*this->_count) == 0)
        {
            delete _count;
            delete _ptr;
        }
        this->_ptr = p._ptr;
        this->_count = p._count;
        return *this;
    }
    ~shared_ptr()
    {
        if ((--*this->_count) == 0)
        {
            delete _ptr;
            delete _count;
        }
        _ptr = NULL;
        _count = NULL;
    }
    int Ret_count()
    {
        return *_count;
    }
private:
    T*_ptr;
    int*_count;
};

2、智能指针可以动态分配对象以及不需要对象时的自动释放,利用auto_ptr来实现。
int*p = new int(0);
auto_ptr ap(p);
我们只管创建,当对象需要释放的时候,auto_ptr会自己释放对象空间。
但是仍然存在一些问题,同一对象不能同时被两个auto_ptr管理,当这一对象需要释放的时候,两个auto_ptr检测到这个对象需要被释放,就会将一个对象释放两遍,会造成程序出问题,即同一对象被释放两遍,类似于malloc与free、new与delete、new[ ]与delete[ ],是有问题的。
auto_ptr,管理权有可能转移,带有严重缺陷的设计方法。
这里严重的缺陷即是会使某些指针悬空,不能很好的管理指针。

//ap2=ap3
Auto_Ptr<T>& operator=(Auto_Ptr<T>&ap)
{
    if(this!=&ap)
    {
        if(_ptr)
        {
            delete _ptr;
        }
        _ptr=ap._ptr;
        ap._ptr=NULL;
    }
    return *this;
}

3.scoped_ptr也是一种简单的智能指针,与auto_ptr类似,通过管理对象达到自动释放对象的效果,但是scoped_ptr与auto_ptr不同点在于,scoped_ptr的拷贝构造函数是私有访问的,也就意味着scoped_ptr不允许调用拷贝构造函数,以及作为函数返回值的赋值重载函数,而auto_ptr可以。scoped_ptr只声明不重载。

    Scoped_Ptr(T*ptr)
        :_ptr(ptr)
    {}
    ~Scoped_Ptr()
    {
        delete[]_ptr;
    }
    T& operator[](size_t pos)
    {
        return _ptr[pos];
    }
protected:
    Scoped_Ptr(const Scoped_Ptr<T>&s);

4.weak_ptr是shared_ptr的辅助装置,并不占用引用次数。

但是,shared_ptr有一个问题,类内在实例化前,成员函数的成员变量调用是可以用this指针来调用的 ,可是this指针并不包括在shared_ptr的引用次数里,这里就是裸传了this这个指针,然而却没对其进行相应的管理,如果在函数调用的过程中间接使用this指针而使得对象被释放,就会产生问题。

循环引用

struct ListNode
{
    ListNode*_prev; //Shared_Ptr<ListNode> _prev;声明
    ListNode*_next; //Shared_Ptr<ListNode> _next;
};

以双链表为例,构造函数初始化阶段相当于定义阶段,如果不显示化构造函数,编译器默认构造缺省的构造函数,初始化的时候赋给随机值。但是有例外,const的变量初始化时候必须赋值,当引用别名的时候也得初始化,类的成员变量在初始化调用构造函数来初始化。

但是循环利用就会有问题,
这里写图片描述
循环引用会导致内存没有释放【内存泄漏】
利用weak_ptr的弱引用指针可以解决循环引用带来的智能指针混乱的问题。

利用_refCount内存的计数次数来控制,只要_refCount不为NULL,内存就不会释放,当_refCount–至0后,然后就会释放空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值