歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C++裡被人遺忘的智能指針

C++裡被人遺忘的智能指針

日期:2017/3/1 9:56:20   编辑:Linux編程

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);&nbsp;<span >}</span>

最為關鍵的就是其析構函數,析構函數中,可以發現的是誰擁有該資源,誰負責釋放

~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();&nbsp;<span >}//釋放掉_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
}

Copyright © Linux教程網 All Rights Reserved