歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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);&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