zoukankan      html  css  js  c++  java
  • [置顶] C++里被人遗忘的智能指针

    1:C++中可不可以自动管理内存的释放功能?

    2:C++里面的智能指针究竟是如何实现的?

    3:以下代码去掉注释与未去掉注释的结果是什么?

    #include<iostream>
    #include<memory>
    #include<new>
    using namespace std;
    void * operator new(size_t size,int data,char *flags)
    {
    	return ::operator new(size);
    }
    void operator delete(void *tmp)
    {
       cout<<"delete"<<endl;
       free(tmp);
    }
    int main()
    {
    	int *tmp=new (10,NULL)int[10];
    	//auto_ptr<int> pInt(tmp);
    	return 0;
    }

    内存申请后最容易被人遗忘的操作就是内存的回收,一个良好的程序员在C/C++中必定记得的是一个new对应一个delete(其实new与delete未必申请与释放内存,想知道为什么,可以看我的博客中你真的了解NEW操作符吗:)),一个malloc对应一个free,那么C++中有没有自动回收内存的机制呢,答案是有

    那就是auto_ptr指针,也许有些人压根就没听说过,也许有些人听说了但是嫌它的功能不够强大,改投了Boost库,作为C++语言的内置特性,还是有必要了解与分析一下,程序员都是比较懒的,释放内存就交给它吧:)

    MSDN中关于它的定义如下:

    Wraps a smart pointer around a resource that ensures the resource is destroyed automatically when control leaves a block.

    翻译过来的的意思就是资源的智能指针,当不再使用该资源时,能够自动释放该资源所占用的内存。

    其源代码定义在<memory>这个文件中,如下:

    template<class _Ty>
    	class auto_ptr {
    public:
    	typedef _Ty element_type;
    	explicit auto_ptr(_Ty *_P = 0) _THROW0(): _Owns(_P != 0), _Ptr(_P) {}
    	auto_ptr(const auto_ptr<_Ty>& _Y) _THROW0()
    		: _Owns(_Y._Owns), _Ptr(_Y.release()) {}
    	auto_ptr<_Ty>& operator=(const auto_ptr<_Ty>& _Y) _THROW0()
    		{if (this != &_Y)
    			{if (_Ptr != _Y.get())
    				{if (_Owns)
    					delete _Ptr;
    				_Owns = _Y._Owns; }
    			else if (_Y._Owns)
    				_Owns = true;
    			_Ptr = _Y.release(); }
    		return (*this); }
    	~auto_ptr()
    		{if (_Owns)
    			delete _Ptr; }
    	_Ty& operator*() const _THROW0()
    		{return (*get()); }
    	_Ty *operator->() const _THROW0()
    		{return (get()); }
    	_Ty *get() const _THROW0()
    		{return (_Ptr); }
    	_Ty *release() const _THROW0()
    		{((auto_ptr<_Ty> *)this)->_Owns = false;
    		return (_Ptr); }
    private:
    	bool _Owns;
    	_Ty *_Ptr;
    	};

    以上代码中可以得到的是智能指针是通过模板进行实现的,是的,也只能如此:),这就是泛型

    首先看看它的两个数据成员

    	bool _Owns;//代表的是该智能指针是否拥有该资源
    	_Ty *_Ptr;//该指针指向内存中开僻的资源,

    其次是构造函数

    explicit auto_ptr(_Ty *_P = 0) _THROW0(): _Owns(_P != 0), _Ptr(_P) {}

    可以清楚的看到的是当成功开僻了一个资源,则_p!=0,然后将智能指针数据成员里的_Ptr指向资源,并设置为拥有该资源。

    再次拷贝构造函数

    	auto_ptr(const auto_ptr<_Ty>& _Y) _THROW0()
    		: _Owns(_Y._Owns), _Ptr(_Y.release()) {}

    在拷贝构造函数中,可以得出的结论是一个资源只有由一个智能指针所拥有,当拷贝构造函数调用时,先前拥有该智能指针的对像将会释放,即_Y.release(),如果同时被两智能指针有拥有,释放资源时将会产生错误

    	_Ty *release() const _THROW0()
    		{((auto_ptr<_Ty> *)this)->_Owns = false;//设置基不再拥有该指资源,并返回该资源的指针
    		return (_Ptr); }


    最为关键的就是其析构函数,析构函数中,可以发现的是谁拥有该资源,谁负责释放

    	~auto_ptr()
    		{if (_Owns)
    			delete _Ptr; }

    然后还有一个比较重要的函数就是其赋值函数,如下

    auto_ptr<_Ty>& operator=(const auto_ptr<_Ty>& _Y) _THROW0()
    {if (this != &_Y)//判断两个对象是否是同一个对象的,是的话直接返回
    {if (_Ptr != _Y.get())//如果不是同一个对象,判断是否指向了同一个资源
    {if (_Owns)//如果未指向同一个资源的话,将原对像的资源先释放,再指向新资源
    delete _Ptr;
    _Owns = _Y._Owns; }
    else if (_Y._Owns)//如果指向同一个资源,标识其拥有该资源
    _Owns = true;
    _Ptr = _Y.release(); }//释放掉_Y对资源的拥有,并该回资源的指针
    return (*this); }

    好了,终于到最后了,最后是三个比较简单的函数,不作解释

    	_Ty& operator*() const _THROW0()
    		{return (*get()); }
    	_Ty *operator->() const _THROW0()
    		{return (get()); }
    	_Ty *get() const _THROW0()
    		{return (_Ptr); }

    最后是一个例子,已经注释,例子中使用了printf而没有使用cout,大家可以自已想想

    #include<iostream>
    #include<memory>
    #include<new>
    using namespace std;
    //重载的new
    void * operator new(size_t size,int data,char *flags)
    {
    	return ::operator new(size);
    }
    //重载的delete
    void operator delete(void *tmp)
    {
       cout<<"delete"<<endl;
       free(tmp);
    }
    int main()
    {
    	int *tmp=new (10,NULL)int[10];//调用重载的new
    	*tmp=5;
    	auto_ptr<int> pInt(tmp);
    	auto_ptr<int> pTmp(pInt);
    	printf("%d\n",*pTmp);
    	//cout<<*pTmp<<endl;//为什么没有用cout?可以自已想想,
    	return 0;//释放时调用重载的delete
    }
  • 相关阅读:
    java读取jar包中的文件
    mysql 常用命令搜集
    如何终端自动导入cer开发证书到钥匙串
    解决第三方库私有api造成的apple审核不通过。
    push证书过期,不需要升级客户端。
    mac下面新建qq(多开/打开多个)登录方法
    行动力才是王道
    wordpress | 网站访问速度优化方案(Avada)
    HTML | video的封面平铺方法
    PHP | 获取数组长度的方法
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3122997.html
Copyright © 2011-2022 走看看