智能指针 auto_ptr/scoped_ptr/shared_ptr/weak_ptr

一:智能指针的发展历史

1、为什么要引入智能指针?

因为存在以下情景:

#include<iostream>
using namespace std;

void F1()
{
    int* tmp = new int;
    return;//这句代码跳出本函数
    delete tmp;//这里并没有得到释放
}

int main()
{
    F1();//F1函数中存在内存泄露
    return 0;
}

当new 与 delete 配对使用时,在delete的中间有一些譬如break、return、continue、exit之类的语句,程序直接跳出了,那new出来的空间就没有释放,那样就会造成内存泄漏的
因此为了解决类似这样的问题,引入智能指针。
2、智能指针发展阶段
①auto_ptr(管理权的转移)
②scoped_ptr(防拷贝)
③shared_ptr(引用技术)
智能指针采用RAII机制,通过对象来管理指针,构造对象时,完成资源的初始化;析构对象时,对资源进行清理及汕尾.

二:细说三大智能指针

①auto_ptr(管理权的转移)
描述:它是直接把指针交给下一个 具有管理权的指针,在把自身置为NULL
缺陷: 不符合指针的使用,它将原来指向那块儿空间的指针置为NULL。
这里写图片描述

模拟实现:

class AutoPtr  
{  
public:  
    AutoPtr(T* ptr = 0)//构造函数  
        :_ptr(ptr)  
    {  
        ptr = NULL;  
    }  

    AutoPtr(AutoPtr<T>& ap)//拷贝构造函数  
        :_ptr(ap._ptr)  
    {  
        ap._ptr = NULL;  
    }  

    AutoPtr<T>& operator=(AutoPtr<T>& ap)//赋值运算符重载  
    {  
        if (this != &ap)  
        {  
            if (_ptr)  
            {  
                delete _ptr;  
            }  
            _ptr = ap._ptr;  
            ap._ptr = NULL;  
        }  
        return *this;  
    }  

    ~AutoPtr()//析构函数  
    {  
        if (_ptr)  
        {  
            delete _ptr;  
            _ptr = NULL;  
        }  
    }  

    T& operator*()  
    {  
        return *_ptr;  
    }  

    T* operator->()  
    {  
        return _ptr;  
    }  
private:  
    T* _ptr;  
};  

void Test1()  
{  
    AutoPtr<int> ap(new int(1));  
    AutoPtr<int> ap1(ap);  
    AutoPtr<int> ap2;  
    ap2 = ap1;  
}  

②scoped_ptr(防拷贝)
描述:守卫指针,防止拷贝。
scoped_ptr与auto_ptr类似,但最大的区别就是它不能转让管理权.也就是说,scoped_ptr禁止用户进行拷贝与赋值。即我们将拷贝构造函数与赋值运算符重载的访问限定符设置为private,并且只给出其声明就行了。
缺陷:解决方法太暴力,还是不能同时有两个指针指向同一块儿空间
模拟实现

template<class T>  
class ScopedPtr  
{  
public :  
    ScopedPtr(T* ptr)//构造函数  
        :_ptr(ptr)  
    {}  
    ~ScopedPtr()//析构函数  
    {  
        if (NULL != _ptr)  
        {  
            delete _ptr;  
            _ptr = NULL;  
        }  
    }  

    T& operator*()  
    {  
        return *_ptr;  
    }  

    T* operator->()  
    {  
        return _ptr;  
    }  
private :  
    ScopedPtr(const ScopedPtr& ap);//拷贝构造函数声明  
    ScopedPtr& operator=(const ScopedPtr& ap);//赋值运算符重载函数声明  
    T* _ptr;  
};  
void TestScopedPtr()
{
    ScopedPtr<int> sp1(new int(10));
    ScopedPtr<int> sp2(new int(20));
    //ScopedPtr<int> sp3(sp1);        //错误
    //sp1 = sp2                     //错误
}

③shared_ptr(引用计数)
描述:在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。即:在本例中我们通过count变量来记录当前有多少个对象共同维护着这个指针,每次拷贝/赋值的时候,让count++.
模拟实现
template
class SharedPtr{
public:
//构造函数
SharedPtr(T *ptr=NULL)
:_ptr(ptr)
,_count(NULL){
if(ptr!=NULL){
_count = new int(1);
std::cout<<_ptr<<” Is Created”<

#include<iostream>  
#include<memory>
using namespace std;

struct Node
{
    shared_ptr<Node> _pre;
    shared_ptr<Node> _next;
    int data;
    ~Node()
    {
        cout << "~Node():" << this << endl;
    }
};

void FunTest()
{
    shared_ptr<Node> Node1(new Node);
    shared_ptr<Node> Node2(new Node);
    Node1->_next = Node2;
    Node2->_pre = Node1;

    cout << "Node1.use_count:" << Node1.use_count() << endl;
    cout << "Node2.use_count:" << Node2.use_count() << endl;
}

int main()
{
    FunTest();
    return 0;
}

运行结果
这里写图片描述

说明
shared_ptr的使用使得一块空间有两个对象管理,即头个结点的_next域和下一个指针共同管理,或者又头一个指针和第二个结点的_ptr域共同管理所以其_pCount=2,因此同样造成了内存泄露。

weak_ptr的出现就是为了辅助shared_ptr的工作,弥补shared_ptr的不足,解决shared_ptr造成的循环引用问题。
因此将上述代码改成

#include<memory>  
#include<iostream>  
using namespace std;  

struct Node  
{  
    weak_ptr<Node> _pre;  
    weak_ptr<Node> _next;  
    int data;
    ~Node()  
    {  
        cout << "~Node():" << this << endl;  
    }    
};  

void FunTest()  
{  
    shared_ptr<Node> Node1(new Node);  
    shared_ptr<Node> Node2(new Node);  
    Node1->_next = Node2;  
    Node2->_pre = Node1;  

    cout <<"Node1.use_count:"<< Node1.use_count() << endl;  
    cout <<"Node2.use_count:"<< Node2.use_count() << endl;  
}  

int main()  
{  
    FunTest();    
    return 0;  
}

结果
这里写图片描述
这样就解决了循环引用的问题,内存就得到了相应的释放。

这里有对比一下C++11与boots库中的,来源:https://blog.csdn.net/zy19940906/article/details/50470087,这是c++11中的智能指针与boost库中的比较,原本boost就是为完善auto_ptr搞得这些,现在c++11有了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值