c++ 中的重載全局new,delete

    最近作一個小項目,對c++又有不少新的理解。實在不的不讓人發出感嘆,c++太強大了,絕對不是一朝一夕就能夠領悟她的內涵的。

       首先咱們要清楚,爲何咱們要重載new,和delete了?這還不是指針形成的,確實指針是一件讓人喜歡的東西,用起來如此讓人喜歡,讓人順手。然而小程序咱們徹底能夠避免內存泄露問題,大程序就不那麼容易了,然而咱們有一種特別好的方法能夠跟蹤咱們new,和delete動做,找到未被釋放的內存。辦法是什麼呢?微軟給咱們提供了一種很好的方法,那就是重載new,和delete。

       在實現以前咱們要清楚new,和delete的工做機理,這是個多麼好的學習機會啊!

       對與new操做符,其實和sizeof同樣,都是c++內置的,然而像strlen就不是了,strlen屬於函數。對於new的功能咱們是沒有辦法改變的,當咱們new一個對象時,new爲咱們作了兩件事情,1、申請一塊足夠的內存空間供存放對象,對於new一個數組對象,編譯器會計算出總共的空間,而後執行相似c語言中malloc函數相似的功能。2、初始化對象,對於單個對象,包括包括基本對象和類對象,能夠經過括號初始化,好比int * pn = new int(3); A * pa = new A(3);   然而對於數組不能初始化,對於類對象,必須定義無參數的構造函數。對與new的基本功能咱們是沒法改變的。

       咱們所能改變的就是如何爲對象分配內存,咱們可一重載這個函數以實現分配內存。一般的重載方式是:

       void * operator new (size_t size);

       然而這已經足夠了,在通常的operator new 重載函數裏,咱們能夠再加入其它參數,但第一個參數必須是size_t類型,即爲無符號整形。正是有這種特性,爲咱們對內存申請和釋放的跟蹤提供了可能。


       具體實現就是第一個operator new 的重載函數,咱們第一的這個函數是這樣的:ios

 
  1. void * operator new(unsigned int size, const char *file, int line)c++

  2. {小程序

  3. cout << "new size:" << size << endl;數組

  4. cout << file << " " << line << endl;函數

  5.  
  6. void * p = malloc(size);學習

  7.  
  8. return p;指針

  9. }code


       而後用宏替換全部的new:

#define new new(__FILE__, __LINE__)

       這樣咱們每次調用new,好比int * pn = new int;被編譯器替換成了int * pn = new (__FILE__, __LINE__) int,從而調用咱們定義的operator new,這種辦法確實很妙。須要交代的是,對於數組一樣適用,而是在編譯的是後由編譯器計算出所須要的長度調用咱們定義的operator new函數。

       對於delete,咱們無需使用宏定義,只要重載operator delete就能夠了,然而咱們須要重載兩個delete:對象

 
  1. void operator delete(void * p)內存

  2. {

  3. cout << "delete " << (int)p << endl;

  4. free(p);

  5. }

  6.  
  7. void operator delete [] (void * p)

  8. {

  9. cout << "delete [] " << (int)p << endl;

  10. free(p);

  11. }


       其實後面一個函數的內容和前面的內容同樣,但爲了支持數組的釋放,咱們必須是要定義的。那麼咱們只是簡單的free(p)編譯器咋知道咱們釋放的數組,仍是單個對象了,這個不用咱們操心了,咱們只要提供給free函數一個申請內存的首地址就能夠了。由於在用malloc申請的時候,咱們也把數組裝換爲內存大小了。

       由此咱們能夠得出下面的推斷:用int * pn = new int [100];的空間,用delete pn釋放和delete [] pn釋放效果同樣。然而那麼既然這兩種方式同樣,那還要delete [] 幹什麼,其實delete [] 有另外的做用就是類對象數組的釋放,編譯器把delete []解釋爲調用對象的析構函數,這個是經過循環實現的,最後釋放掉申請的內存。

       既然咱們已經跟蹤了new和delete,那麼就能夠比較容易的判斷申請的內存是否最後獲得釋放,要完成它,咱們還須要一個鏈表,或者其它,當咱們申請一塊內存的時候加入到鏈表中,釋放一塊空間的時候,從鏈表中刪除和釋放內存首地址相同的節點就能夠了,最後理想的狀況是鏈表爲空,若是不爲空,那就說明內存發生泄露(Memory leaks)了。

完整代碼:

 
  1. #include "malloc.h"

  2. #include "iostream.h"

  3.  
  4. #ifdef _DEBUG

  5.  
  6. void * operator new(unsigned int size, const char *file, int line)

  7. {

  8. cout << "new size:" << size << endl;

  9. cout << file << " " << line << endl;

  10.  
  11. // 下面兩種方法能夠達到一樣的效果,但下面一種比較好

  12. // 由於用下面一種能夠保持原有的申請方式同樣

  13. //void * p = malloc(size);

  14. void * p = operator new(size);

  15.  
  16. return p;

  17. }

  18.  
  19. void operator delete(void * p)

  20. {

  21. cout << "delete " << (int)p << endl;

  22. free(p);

  23. }

  24.  
  25. void operator delete [] (void * p)

  26. {

  27. cout << "delete [] " << (int)p << endl;

  28. free(p);

  29. }

  30.  
  31. void operator delete(void * p, const char *file, int line)

  32. {

  33. cout << "delete file line" << endl;

  34. free(p);

  35. }

  36.  
  37. void operator delete [] (void * p, const char *file, int line)

  38. {

  39. cout << "delete [] file line" << endl;

  40. free(p);

  41. }

  42.  
  43. #define new new(__FILE__, __LINE__)

  44. #endif

  45.  
  46. void main()

  47. {

  48. int * p = new int[5];

  49. delete [] p;

  50. // delete p;

  51. }


原文:http://hi.baidu.com/123az/item/d5a4768c2afee3c498255f18

 

筆者:Visual studio中使用CRT庫來檢測內存泄漏的原理就是重載全局的new、delete。

相關文章
相關標籤/搜索