Chinaunix首页 | 论坛 | 博客
  • 博客访问: 747838
  • 博文数量: 239
  • 博客积分: 60
  • 博客等级: 民兵
  • 技术积分: 1045
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-22 18:25
文章分类

全部博文(239)

文章存档

2019年(9)

2018年(64)

2017年(2)

2016年(26)

2015年(30)

2014年(41)

2013年(65)

2012年(2)

分类: C/C++

2013-01-25 14:36:14

    C++有关new/delete的头文件之一 是标准库,   operator new/delete可以参考;  new/delete 和operator new/delete是存在相当大的差别的.在VS2005上测试下列代码:

点击(此处)折叠或打开

  1. #include
  2. #include
  3. #include
  4. using namespace std;
  5. //#define NEW_ARRAY
  6. //#define NEW_OPRATOR
  7. //#define NEW_FAIL_OPERATOR
  8. //#define NEW_HANDLER
  9. #if defined(NEW_HANDLER)
  10. void my_handler()
  11. {
  12. cout <<"void my_handler() called"<
  13. throw bad_alloc();
  14. }
  15. #endif//NEW_HANDLER
  16. struct myclass
  17. {
  18. myclass()
  19. {
  20. cout <<"myclass constructed\\n";
  21. }
  22. ~myclass()
  23. {
  24. cout <<"myclass deconstructed\\n";
  25. }
  26. virtual void testmyclass()
  27. {
  28. cout <<"myclass testmyclass called\\n";
  29. }
  30. };
  31. class base
  32. {
  33. public:
  34. base()
  35. {
  36. cout <<"base constructed sizeof(*this)="<
  37. }
  38. virtual ~base()
  39. {
  40. cout <<"base deconstructed\\n";
  41. }
  42. };
  43. class superClass : public base
  44. {
  45. public:
  46. superClass()
  47. {
  48. cout <<"superClass constructed sizeof(*this)="<
  49. #if defined(NEW_FAIL_OPERATOR)
  50. throw bad_alloc();
  51. #endif//NEW_FAIL_OPERATOR
  52. #if defined(NEW_HANDLER)
  53. #define BIG_SIZE 0x7fffffff
  54. new char[BIG_SIZE];
  55. #endif//NEW_HANDLER
  56. }
  57. superClass(int a)
  58. {
  59. cout <<"superClass constructed a="<
  60. }
  61. ~superClass()
  62. {
  63. cout <<"superClass deconstructed\\n";
  64. }
  65. void* operator new (std::size_t s) throw (std::bad_alloc)
  66. {
  67. void *p = malloc(s);
  68. cout <<"operator new(size_t s) called ; s="<
  69. return p;
  70. }
  71. void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw()
  72. {
  73. void *p = malloc(s);
  74. cout <<"void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw(); s="<
  75. return p;
  76. }
  77. void * operator new(size_t, void *_Where) throw()
  78. {
  79. try
  80. {
  81. cout <<"operator new(size_t, void *_Where) called; strlen(_Where)="<
  82. return (_Where);
  83. }
  84. catch (...)
  85. {
  86. }
  87. // construct array with placement at _Where
  88. cout <<"operator new(size_t, void *_Where) called; strlen(_Where)="<
  89. return (_Where);
  90. }
  91. void* operator new[](size_t s) throw()
  92. {
  93. void *p = malloc(s);
  94. cout <<"void* operator new[](size_t count) throw(std::bad_alloc) called; s="<
  95. return p;
  96. }
  97. void* operator new[](size_t s, const std::nothrow_t&) throw()
  98. {
  99. void *p = malloc(s);
  100. cout <<"void* operator new[](size_t count, const std::nothrow_t&) throw() called ; s="<
  101. return p;
  102. }
  103. void* operator new[](size_t s, void* object) throw()
  104. {
  105. try // has been constructed before current
  106. {
  107. cout <<"void* operator new[](size_t s, void* object) throw() called; s="<
  108. return (object);
  109. }
  110. catch (...)
  111. {
  112. }
  113. cout <<"void* operator new[](size_t s, void* object) throw() called; s="<
  114. return object;
  115. }
  116. void operator delete (void* _Where) throw ()
  117. { // construct array with placement at _Where
  118. cout <<"void operator delete (void* _Where) throw () called; strlen(_Where)="<
  119. free(_Where);
  120. return ;
  121. }
  122. void operator delete (void* p, const std::nothrow_t& nothrow_constant) throw()
  123. {
  124. cout <<"void operator delete (void* p, const std::nothrow_t& nothrow_constant) throw() called; strlen(p)="<
  125. free(p);
  126. return ;
  127. }
  128. void operator delete (void* ptr, void* voidptr2) throw()
  129. {
  130. cout <<"void operator delete (void* ptr, void* voidptr2) called; strlen(ptr)="<
  131. return ;
  132. }
  133. void operator delete[] (void* p) throw ()
  134. {
  135. cout <<"void operator delete[] (void* ptr) throw ()) called; strlen(p)="<
  136. free(p);
  137. return ;
  138. }
  139. void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw()
  140. {
  141. cout <<"void operator delete[] (void* p, const std::nothrow_t& nothrow_constant) throw() called \\n";
  142. free(p);
  143. return ;
  144. }
  145. void operator delete[] (void* ptr, void* voidptr2) throw()
  146. {
  147. cout <<"void operator delete[] (void* ptr, void* voidptr2) throw() called; strlen(ptr)="<
  148. return ;
  149. }
  150. };
  151. int main(int argc, char* argv[])
  152. {
  153. #if defined(NEW_HANDLER)
  154. new_handler old_handler = set_new_handler(my_handler);
  155. superClass * pHandlerMem = NULL;
  156. try
  157. {
  158. pHandlerMem = new superClass;
  159. }
  160. catch (...)
  161. {
  162. cout <<"pHandlerMem = new superClass; exception"<
  163. }
  164. #endif//
  165. #if defined(NEW_ARRAY)
  166. // uses first version:
  167. int * pa1 = new int[5];
  168. // uses second version:
  169. int * pa2 = new (nothrow) int[4];
  170. // uses third version:
  171. //pair pa3 = get_temporary_buffer(3);
  172. //new (pa3.first) myclass[3]; // calls constructors
  173. //return_temporary_buffer(pa3.first);// cut from %20new[]/
  174. int superClassSize = sizeof(superClass);
  175. superClass *paBase = NULL;
  176. superClass *pArryCon = NULL;
  177. try
  178. {
  179. cout <<"paBase = (superClass *) operator new[](2 * superClassSize);"<
  180. paBase = (superClass *) operator new[](2 * superClassSize);
  181. pArryCon = new (paBase) superClass[2];
  182. delete pArryCon;
  183. paBase = NULL;
  184. cout <<"paBase = new superClass[2];"<
  185. paBase = new superClass[2];
  186. delete paBase;
  187. paBase = NULL;
  188. cout <
  189. paBase = (superClass *)superClass::operator new[](2 * superClassSize);
  190. superClass::operator delete[](paBase, (void*)paBase);
  191. paBase = NULL;
  192. cout <<"paBase = (superClass *) new (nothrow) const superClass[2];"<
  193. paBase = (superClass *) new (nothrow) const superClass[2];
  194. delete paBase;
  195. paBase = NULL;
  196. //paBase = new superClass[2];
  197. //paBase = (superClass *)superClass::operator new[](paBase);
  198. //superClass::operator delete[](paBase, (void*)paBase);
  199. //throw;
  200. }
  201. catch (...)
  202. {
  203. cout <<"catch (...)"<
  204. //delete [] paBase;
  205. return 0;
  206. }
  207. //superClass *paBase = new superClass[5];
  208. //delete[](paBase);
  209. //superClass *paBase = (superClass *)superClass::operator new[](20);
  210. //superClass::operator delete[](paBase);
  211. //superClass *paOpBase = operator new[](sizeof(superClass));
  212. #endif//NEW_ARRAY
  213. #if defined(NEW_OPRATOR)
  214. cout <<"superClass *pBase = new (nothrow) superClass;"<
  215. superClass *pBase = new (nothrow) superClass;
  216. delete pBase ;
  217. cout <<"pBase = (superClass *)superClass::operator new (sizeof(superClass));"<
  218. pBase = (superClass *)superClass::operator new (sizeof(superClass));
  219. superClass * pPlace = new (pBase) superClass;
  220. // delete pBase;
  221. pPlace->~superClass();
  222. superClass::operator delete(pBase);
  223. //new (pBase) superClass;
  224. cout <<"const superClass *pBase3 = new const superClass();"<
  225. const superClass *pBase3 = new const superClass();
  226. delete pBase3;
  227. cout <<"size_t s = sizeof(superClass);"<
  228. size_t s = sizeof(superClass);
  229. superClass *pBase2 = (superClass *)operator new (s);
  230. superClass * pBase5 = new (pBase2) superClass(1);
  231. pBase5->~superClass();
  232. operator delete(pBase5);
  233. //delete pBase5;
  234. cout <<"pBase2 = (superClass *)new superClass;"<
  235. pBase2 = (superClass *)new superClass;
  236. new (pBase2) superClass;
  237. pBase2->~superClass();
  238. operator delete(pBase2);
  239. int * p1 = new int;
  240. // same as:
  241. // int * p1 = (int*) operator new (sizeof(int));
  242. int * p2 = new (nothrow) int;
  243. // same as:
  244. // int * p2 = (int*) operator new (sizeof(int),nothrow);
  245. myclass * p3 = (myclass*) operator new (sizeof(myclass));
  246. // (!) not the same as:
  247. // myclass * p3 = new myclass;
  248. // (constructor not called by function call, even for non-POD types)
  249. p3->testmyclass();
  250. new (p3) myclass; // calls constructor
  251. // same as:
  252. // operator new (sizeof(myclass),p3)
  253. //delete p3;
  254. operator delete(p3);
  255. int delay = 1;
  256. myclass *p4 = new myclass;
  257. delete p4;
  258. p4 = NULL;
  259. #endif //NEW_OPRATOR
  260. return 0;
  261. }
根据如上代码,我们通过控制宏进行如下情况分析:
一. 对象内部因为申请大内存异常情况
. new内存申请, 在对象内部申请大内存,因内存不足的情况, 只打开宏NEW_HANDLER编译运行输出为:

点击(此处)折叠或打开

  1. operator new(size_t s) called ; s=4
  2. base constructed sizeof(*this)=4
  3. superClass constructed sizeof(*this)=4
  4. void my_handler() called
  5. base deconstructed
  6. void operator delete (void* _Where) throw () called; strlen(_Where)=3
  7. pHandlerMem = new superClass; exception
根据输出结果, new对象时先申请内存, 在调用对象的构造函数, 有继承体系的根据继承体系进行调用; 当对象因为申请内存失败没有成功创建, 先调用内存失败处理函数my_handler(), 在内存失败处理函数中在抛出异常, 就再调用创建好的对象的释构函数, 最后在调用相应operator delete进行内存释放, 防止内存泄漏. (但是strlen(_Where) = 3的原因未知.嗨???), 用new进行其他方式进行superClass内存操作情况相似(new, operator new, superClass::operator new 加上放置式).
二. new申请对象内存,对象内部抛出异常 只同时打开宏NEW_FAIL_OPERATOR和NEW_HANDLER, 当用new对象申请对象内存, 对象throw throw bad_alloc(), 将不调用内存失败处理函数my_handler(), 而是直接调用创建好的对象释构函数, 然后调用相应的operator delete进行内在释放. new, new const 和new的放置式调用失败后, 调用的是不同的operator delete. 输出结果为:

点击(此处)折叠或打开

  1. operator new(size_t s) called ; s=4
  2. base constructed sizeof(*this)=4
  3. superClass constructed sizeof(*this)=4
  4. base deconstructed
  5. void operator delete (void* _Where) throw () called; strlen(_Where)=3
  6. pHandlerMem = new superClass; exception
三. operator new/delete配对情况. 只打开示例程序宏NEW_OPRATOR,编译运行输出:

点击(此处)折叠或打开

  1. base deconstructed
  2. void operator delete (void* _Where) throw () called; strlen(_Where)=3
  3. const superClass *pBase3 = new const superClass();
  4. operator new(size_t s) called ; s=4
  5. base constructed sizeof(*this)=4
  6. superClass constructed sizeof(*this)=4
  7. superClass deconstructed
  8. base deconstructed
  9. void operator delete (void* _Where) throw () called; strlen(_Where)=3
  10. size_t s = sizeof(superClass);
  11. operator new(size_t, void *_Where) called; strlen(_Where)=9
  12. base constructed sizeof(*this)=4
  13. superClass constructed a=1
  14. superClass deconstructed
  15. base deconstructed
  16. pBase2 = (superClass *)new superClass;
  17. operator new(size_t s) called ; s=4
  18. base constructed sizeof(*this)=4
  19. superClass constructed sizeof(*this)=4
  20. operator new(size_t, void *_Where) called; strlen(_Where)=3
  21. base constructed sizeof(*this)=4
  22. superClass constructed sizeof(*this)=4
  23. superClass deconstructed
  24. base deconstructed
并在 p3->testmyclass();这一行发生异常。 对着结果分析。
    (1)首先,new (nothrow) superClass 对应void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw();此时delete 对应 void operator delete (void* _Where) throw (). 对着superClass *pBase = new (nothrow) superClass; 这行产生void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw()的调用,然后调用对象的构造函数。 当执行delete pBase ;先调用对象的析构函数, 然后调用 void operator delete (void* _Where) throw ();

    (2) superClass::operator new (sizeof(superClass))对应superClass类中void* operator new (std::size_t s) throw (std::bad_alloc),但是不会调用对象的构造函数,相当于内存分配。 语句new (pBase) superClass并不会分配内存,但它会引起superClass构造函数的调用,对就superClass类中void * operator new(size_t, void *_Where) throw()。 语句pPlace->~superClass();只是调用pPlace所指的对象上调用~superClass这个析构函数,对象本身的内存没有释放,把pPlace->~superClass()当成类似其他成员函数的调用。 语句superClass::operator delete(pBase)对应superClass类中void operator delete (void* _Where) throw ()函数,这种调用不会引起对象析构函数的调用.

点击(此处)折叠或打开

  1. pBase = (superClass *)superClass::operator new (sizeof(superClass));//调用void* operator new (std::size_t s) throw (std::bad_alloc),
  2. superClass * pPlace = new (pBase) superClass;//调用void * operator new(size_t, void *_Where) throw()和对象构造函数
  3. // delete pBase;
  4. pPlace->~superClass();//调用~superClass()和virtual ~base()两个对象析构函数,如果virtual ~base()为~base(),则只调用~superClass()函数
  5. superClass::operator delete(pBase);//只调用superClass类中void operator delete (void* _Where) throw (), 不引起对象析构函数调用
    (3)语句new const superClass()对应superClass类中void* operator new (std::size_t s) throw (std::bad_alloc),并调用对象构造函数。相应的delete 对应superClass类中void operator delete (void* _Where) throw (),并调用相应的析构函数.

点击(此处)折叠或打开

  1. const superClass *pBase3 = new const superClass();//调用void* operator new (std::size_t s) throw (std::bad_alloc)和对象构造函数
  2. delete pBase3;//调用void operator delete (void* _Where) throw ()和对象析构函数
    (4) 语句(superClass *)operator new (s)对应库函数void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc),不调用对象构造函数。语句new (pBase2) superClass(1)对应superClass类中void * operator new(size_t, void *_Where) throw(), 这个称为new 的放置式,此时不会给对象分配内存,而是产生对象superClass(1)构造函数的调用,在相应指定的内存上构造对象。语句pBase5->~superClass()对应调用对象的析构函数。语句operator delete(pBase5)对应库函数void operator delete(void *pUserData), 同时不产生对象的析构函数调用.

点击(此处)折叠或打开

  1. size_t s = sizeof(superClass);
  2. superClass *pBase2 = (superClass *)operator new (s);//库函数void *__CRTDECL operator new(size_t size),不产生构造函数调用
  3. superClass * pBase5 = new (pBase2) superClass(1);//调用superClass类void * operator new(size_t, void *_Where) throw(),产生superClass(1)和base()调用
  4. pBase5->~superClass();//调用~superClass()和virtual ~base()
  5. operator delete(pBase5);//调用库函数void operator delete(void *pUserData), 不产生析构函数调用
    (5)  语句new superClass 对应superClass类void* operator new (std::size_t s) throw (std::bad_alloc),并产生对象构造函数调用。

语句new (pBase2) superClass对应superClass类中void * operator new(size_t, void *_Where) throw(),不产生内存分配,但引起对象构造函数的调用, new superClass和new (pBase2) superClass共引起两上对象构造函数调用,相当的危险。pBase2->~superClass();
对应调用对象析构函数,但是对象内存没有释放。operator delete(pBase2)释放对象内存,但是不产生对象构造函数的调用。虽然pBase2->~superClass()和operator delete(pBase2)组合功能类似delete对象,但是和delete并不相同,特别是superClass::operator delete(pBase2)调用是允许的.

点击(此处)折叠或打开

  1. pBase2 = (superClass *)new superClass;//调用superClass类void* operator new (std::size_t s) throw (std::bad_alloc)和构造函数
  2. new (pBase2) superClass;//调用superClass类void * operator new(size_t, void *_Where) throw()和构造函数。
  3. pBase2->~superClass();//对象析构函数
  4. operator delete(pBase2);//库函数void operator delete( void * p )
     (6) 分析在 p3->testmyclass()这一行发生异常原因。对于类

点击(此处)折叠或打开

  1. struct myclass
  2. {
  3. myclass()
  4. {
  5. cout <<"myclass constructed\\n";
  6. }
  7. ~myclass()
  8. {
  9. cout <<"myclass deconstructed\\n";
  10. }
  11. virtual void testmyclass()
  12. {
  13. cout <<"myclass testmyclass called\\n";
  14. }
  15. };
其中virtual void testmyclass() 说明testmyclass是虚的,语句myclass * p3 = (myclass*) operator new (sizeof(myclass))只是分配内存,并没有把对象构造起来,也就是说对象虚表不存在,调用p3->testmyclass()肯定要异常。如果写成如下,即在调用p3->testmyclass()前先调用把new (p3) myclass对象构造起来,就可以成功调用。(注:如果virtual void testmyclass()改成 void testmyclass()就可以运行通过,不抛出异常,反汇编下就知道了. 又一个C++特性)

点击(此处)折叠或打开

  1. superClass *pBase = new (nothrow) superClass;
  2. void* operator new (std::size_t s, const std::nothrow_t& nothrow_constant) throw(); s=4
  3. base constructed sizeof(*this)=4
  4. superClass constructed sizeof(*this)=4
  5. superClass deconstructed
  6. base deconstructed
  7. void operator delete (void* _Where) throw () called; strlen(_Where)=3
  8. pBase = (superClass *)superClass::operator new (sizeof(superClass));
  9. operator new(size_t s) called ; s=4
  10. operator new(size_t, void *_Where) called; strlen(_Where)=9
  11. base constructed sizeof(*this)=4
  12. superClass constructed sizeof(*this)=4
  13. superClass deconstructed
  14. myclass * p3 = (myclass*) operator new (sizeof(myclass));
  15. // (!) not the same as:
  16. // myclass * p3 = new myclass;
  17. // (constructor not called by function call, even for non-POD types)
  18. //p3->testmyclass();
  19. new (p3) myclass; // calls constructor
  20. p3->testmyclass();
  21. // same as:
  22. // operator new (sizeof(myclass),p3)
  23. //delete p3;
  24. operator delete(p3);
输出如下:

点击(此处)折叠或打开

  1. myclass constructed
  2. myclass testmyclass called
  3. myclass constructed
用operator delete(p3)代替delete p3有可能产生内存泄漏, 因为operator delete()会造成对象析构函数无法被调用. 

    还有其他的new/delete    operator new/operator delete组合方法, 我们看出来operator new/delete在用户调用时,相当于函数调用, 当编译器调用时,就会产生构造或者析构操作.  同时使用new方式的不同,会在异常或者delete后造成不同调用.

 

阅读(1013) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~