smart_pointer

来源:互联网 发布:高德端口修改器 v33 编辑:程序博客网 时间:2024/06/05 21:59

引入:
C++程序员最痛苦的莫过于对内存管理,没有像C#和Java那样的内存回收机制,C++程序员在复杂的程序中容易造成内存泄漏,即便是程序员非常小心,异常的产生也会造成部分内存泄漏。(由于异常而导致delete语句没有释放动态分配的内存)从而引出了智能指针(smart_pointer)。
什么是智能呢?
这种指针实质是一个包装了一个指针的类,通过RAII机制来自动释放内存。下面会详细介绍RAII。通过在类里重载 * 运算符,和->运算符来实现基本指针的操作。
RAII(Resource Acqisition Is Initialzation)的缩写,也就是资源获取继初始化。是一种资源管理,避免内存泄漏的方法。RAII的做法是使用一个对象在构造时获取资源,在对象生命周期结束时自动调用析构函数来释放内存。
C++提供了基本的三种智能指针库里的(auto_ptr ,scoped_ptr)和C++11 boost库里的
shared_ptr.
下面来一一分析以下几个指针:
auto_ptr 第一代智能指针

template<class T>class Auto_ptr{public:    Auto_ptr(T*p=0)        :_ptr(p)    {}    ~Auto_ptr()    {        delete _ptr;        _ptr = NULL;    }T& operator *()    {    return *_ptr;    }T* operator->(){    return _ptr;}T operator=(T&t){    *_ptr = t;}private:    T *_ptr;};class my_struct{public:    my_struct(int i=10,int j=20)        :_i(i)        , _j(j)    {}    int _i;    int _j;};int main(){    Auto_ptr<int> p1(new int(3));     Auto_ptr<my_struct> p2(new my_struct);cout<<"*p1 = "<<*p1<<endl;cout << "p2->_i= "<<p2->_i<<endl;cout <<"p2->_j= "<< p2->_j<<endl;return 0;}

测试:
这里写图片描述

auto_ptr首先具有RAII也就是智能,也具有指针的普通操作。
但以上程序没介绍到赋值运算符重载 和拷贝构造。是因为auto_ptr的赋值运算符重载是一种管理权限转移的操作。如下图
这里写图片描述
要实现p1=p2,假设p1已经指向一块空间,那么就会让p2先指向这块空间,把p1至为空。也就是管理权限转变给了p2,这和我们的初心大相径庭。
而如果两个同时指向一块空间,析构的时候就会把原来的数据给丢失。所以auto_ptr是一个失败的例子。
scoped_ptr解决了auto_ptr的缺陷,也就是只给出了赋值运算符和拷贝构造的定义,并且为了防止恶意破坏,封装在private里。

template<class T>class scoped_ptr{public:    scoped_ptr(T*p = 0)        :_ptr(p)    {}    ~scoped_ptr()    {        delete _ptr;        _ptr = NULL;    }    T& operator *()    {        return *_ptr;    }    T* operator->()    {        return _ptr;    }private:    scoped_ptr(scoped_ptr<T>& ptr);    scoped_ptr<T>& operator=(scoped_ptr<T>& ptr);    T *_ptr;};

最后C++提出了shared_ptr在boost库里,里面运用了引用计数的管理方法进行赋值,等操作。

template<class T>struct Delete{    void operator()(T* ptr)    {        delete ptr;    }};template<class T>//定制的删除数组删除器struct DeleteArray{    void operator()(T* ptr)    {        delete[] ptr;    }};template<class T, class D = Delete<T>>class SharedPtr{public:    SharedPtr(T* ptr)        :_ptr(ptr)        ,_countRef(new int(1))    {}    SharedPtr(const SharedPtr<T, D>& sp)        :_ptr(sp._ptr)        ,_countRef(sp._countRef)    {           ++(*_countRef);    }    SharedPtr<T, D>& operator=(const SharedPtr<T, D>& sp)    {        if(_ptr != sp._ptr)        {            Release();            _ptr = sp._ptr;            use_count = sp.use_count;            ++(*use_count);        }        return *this;    }    inline void Release()    {        if (--(*_countRef) == 0)        {            cout<<_ptr<<endl;            //delete _ptr;            _del(_ptr);            delete _countRef;        }    }    ~SharedPtr()    {        Release();    }    //operator*()    //operator->()    int UseCount()    {        return *_countRef;    }protected:    T* _ptr;        //     int* _countRef; // 引用计数    D _del; // 定制的仿函数删除器};

但是shared_ptr指向一个双链表节点的时候会出现循环引用,也就是这个节点的引用计数是循环的
这里写图片描述
每个节点的引用计数永远是2,产生错误。
为了解决问题 boost库里引入weak_ptr指针解决。包含头文件

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 猪体温低不吃食怎么办 小孩发烧咳嗽怎么办吃什么药 大晚上发烧39度怎么办 胃受凉了老打嗝怎么办 大人发低烧怎么办如何退烧 吃了退热药不退热怎么办 猪持续高烧不退怎么办 猪感冒了不吃食怎么办 6岁儿童发烧38度怎么办 5岁儿童发烧38度怎么办 7岁儿童发烧38度怎么办 儿童发烧到38度怎么办 4岁儿童发烧38度怎么办 9岁儿童发烧38度怎么办 5儿童发烧38度怎么办 咳嗽了20多天怎么办 嘴角烂了怎么办涂什么药 感冒发烧到39度怎么办 6岁宝宝发烧头痛怎么办 生完孩子耻骨疼怎么办 顺产底下外阴红肿伤口流脓怎么办 产后便秘怎么办什么方法最有效 一周岁宝宝拉肚怎么办 三岁宝宝拉水怎么办 喝了过期的青汁怎么办 吃了黑心的苹果怎么办 新生儿两天没拉大便怎么办 贝亲奶瓶不漏怎么办 满月婴儿吃多了怎么办 婴儿吃撑了哭闹怎么办 新生儿吃撑了怎么办啊 新生儿吃了奶粉不吃奶怎么办 新生儿不吃奶也不吃奶粉怎么办 奶瓶吸奶费力不顺畅怎么办 宝宝吃奶粉太勤怎么办 香蕉和地瓜一起吃了怎么办 贝亲奶瓶泡沫多怎么办 四个多月的宝宝拉肚子怎么办 宝宝四个月了拉肚子怎么办 四个月宝宝火大怎么办 刚出生的宝宝便秘怎么办