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。

相关文章
相关标签/搜索