智能指针的进步史(Auto_ptr-----scoped_ptr--------------shared_ptr(weak_ptr))

为什么会有智能指针

之所以引出智能指针是为了解决内存回收问题,就拿抛异常-捕获异常的场景来说吧,我们知道异常捕捉的时候会引起执行流的乱跳,所以假如有些空间是new或者malloc出来的那么我们就要手动的释放,而不确定哪里会捕捉到异常也同样不确定最终异常是否被捕捉,所以为了避免内存泄露,我们就会抛异常时候进行释放,无异常也要释放,但是这仍然有疏漏,有的时候会释放多次,我们就想怎样让这些空间不用的时候就自动释放?

智能指针的发展

说到智能指针,我们就不得不提一提RAII

RAII:资源分配即初始化,及定义一个类专门来管理资源的分配和释放
智能指针就是RAII的实例,

智能指针的思想:
1、借助构造函数来保存资源,无论是否有异常抛出,出了作用域就会自己调用析构函数释放空间
2、智能指针就要像指针一样,具有*和->的功能,代码中会封装这两个功能

1、Auto_Ptr(c++98)

这种的指针是最原始的,主要说一下它的赋值运算、以及拷贝构造,因为在这两种情况下会产生浅拷贝的问题,导致释放空间多次,他有两种解决方案:
一、使用管理权转移
这里写图片描述
当用ap1给ap2赋值(或者拷贝ap2)的时候,就将ap1指向空指针,这样显然不合理(*ap1会出错)
二、每个对象一个owner成员,只让空间拥有者来管理释放

2、scoped_ptr、shared_ptr、weak_ptr(boost库)

一、scoped_ptr是一种简单粗暴的方式,直接将拷贝构造以及赋值运算符重载只声明不定义(防拷贝),并且定义成私有。
这里写图片描述
实现:

#include<iostream>
using namespace std;
template <class T>
class Scoped_ptr{
public:
    Scoped_ptr()
        :_ptr(NULL)
    {}
    ~Scoped_ptr(){
        if (_ptr){
            delete _ptr;
            _ptr = NULL;
        }
    }
    T& operator*(){
        return *_ptr;
    }
    T* operator->(){
        return _ptr;
    }
private:
    Scoped_ptr(const Scoped_ptr& sp);
    Scoped_ptr& operator=(const Scoped_ptr& sp);
    T* _ptr;
};

2、shared_ptr就是来解决scoped_ptr不能拷贝复制的问题而出现的,它采用了引用计数
这里写图片描述
这里写图片描述
实现代码:

template<typename T>
class Shared_ptr{
public:
    Shared_ptr(T* p)
        :_ptr(p)
        , _pCount(new int(1))
    {}
    Shared_ptr(const Shared_ptr& sp){
        _ptr = sp._ptr;
        _pCount = sp._pCount;
        ++(*pCount);
    }
    Shared_ptr& operator=(const Shared_ptr& sp){
        if(_ptr!=sp._ptr){
            if (--(*pCount == 0)){
                delete _ptr;
                delete _pCount;
            }
            _ptr = sp._ptr;
            _pCount = sp._pCount;
            ++(*pCount);
            return *this;
        }
    }
    ~Shared_ptr(){
        if (_ptr){
            delete _ptr;
            _ptr = NULL;
        }
    }
    T& operator*(){
        return *_ptr;
    }
    T* operator->(){
        return _ptr;
    }
private:
    T* _ptr;
    int* _pCount;
};

三、weak_ptr其实只是辅助shared_ptr才产生的因为shared_ptr有循环引用的弊端
这里写图片描述
当出了作用域引用计数都减到1,空间并没有释放,因为想要析构node1就必须依赖于析构了_next,而_next的析构又依赖于node2,node2 的析构同样也依赖于_prev,所以会造成内存泄露。
我们的weak_ptr就是辅助shared_ptr,在循环引用的情况下不增加引用计数,检测对象是否被释放。

猜你喜欢

转载自blog.csdn.net/cx2479750196/article/details/80634903