CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C++ 语言

memory leak问题?

楼主cpp_wq(天天C++)2006-02-03 17:51:19 在 C/C++ / C++ 语言 提问

各位朋友,我有一个问题,想请教大家,下面是一个示范程序,没有任何实际意义。  
   
  class   foo  
  {  
  public:  
        foo():a(0)   {   pi   =   new   int(3);}  
  private:  
        int   a;  
        int   *pi;  
  };  
  void   test()  
  {  
          foo   *pf   =   new   foo();  
          //do   something   with   pf  
          delete   pf;  
  }  
  大家知道,“foo   *pf   =   new   foo(4);”这条语句的执行分为两个方面:  
  1.调用operator   new()分配sizeof(foo)大小的raw   memory;  
  2.调用foo类的构造函数对1中分配的内存进行初始化。  
  那么,如果在第2步中出现异常,即调用constructor时出现异常,从而退出test()函数,便会导致内存泄漏问题。有人可能会想到,利用try...catch进行异常捕获:  
  void   test()  
  {  
          try{  
                foo   *pf   =   new   foo();  
                //do   omething   with   pf  
          }  
          catch(...){  
                delete   pf;  
                throw;  
          }  
          delete   pf;  
  }  
  可问题是,如果调用constructor时出现异常,即对象没有被构造完全,pf是不会被正确赋值的(即pf不会被赋为1中分配的内存的起始地址),所以上述方法也不适用。  
   
  那我想请教各位高手,像这种内存泄漏问题,应该怎么解决呢?(   用所谓的"placement   delete"方法?---好像此方法不是普遍使用的呀:(   ) 问题点数:50、回复次数:20Top

1 楼ericqxg007(还有很多东西要学(卡卡一米阳光))回复于 2006-02-03 18:10:09 得分 0

那你就在constructor里面写一个异常处理  
   
  另外提示一下:    
          在构造函数里面写了new   别忘了在析构函数里面写个deleteTop

2 楼hu_vane(边学边发现自己的无知)回复于 2006-02-03 18:49:13 得分 0

constructor中抛个异常就行了Top

3 楼cpp_wq(天天C++)回复于 2006-02-03 20:47:40 得分 0

to   楼上二位:  
   
      你们好像没看懂我的问题。  
       
      “在constructor里面写上一个异常处理”只能够释放“本对象的指针成员”所指向的内存区域,却无法释放“当前对象”所占用的内存(在上面的程序中,当前对象即位pf指针所指向的foo对象,它也分配在heap上,而不是在stack上)。  
  Top

4 楼ericqxg007(还有很多东西要学(卡卡一米阳光))回复于 2006-02-03 21:05:08 得分 0

try{  
                foo   *pf   =   new   foo();  
                //do   omething   with   pf  
          }  
          catch(...){  
                delete   pf;  
                throw;  
          }  
   
        你本身代码都有问题,既然没有new成功你delete干什么?  
        一般我不用异常   直接判断指针是不是空就可以了    
        new   异常在编译器会有默认的异常处理Top

5 楼cpp_wq(天天C++)回复于 2006-02-04 13:12:01 得分 0

to   ericqxg007(一笑而过):  
   
      的确,你说的没错,是“没有new成功”,但是那是new   expression的第二步(调用构造函数时)出现的问题,而第一步(调用operator   new分配raw   memory)已经成功完成,所以我的意思是,如何将这个已经分配的raw   memory还给系统。难道你所说的“new   异常在编译器会有默认的异常处理”便能释放所分配的raw   memory?Top

6 楼ox_thedarkness()回复于 2006-02-04 13:34:45 得分 0

to   一笑而过  
  判断指针为空是不符合现在C++标准的。参考   Effect   C++   条款8  
   
  在1993年以前,C++要求new失败时返回0;但是现在C++中   new   只会抛出   std::bad_alloc异常。  
  所以在现在的编译器上,if(   pf     ){...}测试要么成立,要么处在流程之外(异常抛出)  
   
  如果要使用旧式返回0的异常,则应该使用nothrow(头文件<new>中)形式的new  
   
  A*   pa   =   new(   nothrow   )   A;  
  if(   pa   )         //   Ok  
  Top

7 楼ox_thedarkness()回复于 2006-02-04 14:08:24 得分 0

对于楼主的问题,答案是必须用很麻烦的办法。  
  一般来说,C++有一个规则就是不能在constructor中抛出异常(虽然这是允许的,但是会诱发mem   leak,如楼主所言)  
   
  一个常见的解决方案是提供   init   函数,把所有要求资源申请都集中到init   函数中。这样   constructor就不会抛出异常了。类似:  
   
  foo*   pf   =   0;  
  try{  
      pf   =   new   foo();       //   只有foo的   new会抛出std::bad_alloc   异常。  
      pf->init();                         //   其他异常在这里抛出  
  }catch(   ...   ){  
      if(   !pf   ){     //   foo的   new失败。  
      }   else   {         //   pf->init()异常  
      }  
  }Top

8 楼vollin(林尚义)回复于 2006-02-04 14:59:37 得分 0

ox_thedarkness()   (   )   信誉:100    
   
  同意,在构造中使用异常是件非常麻烦的事。Top

9 楼zmjsx(风向)回复于 2006-02-04 15:47:58 得分 0

我有个办法你看看可行不?你用汇编写个内存占用控制,某命令调用申请了内存地址后,如果一段时间内未写入,就将此次调用视作误操作。Top

10 楼rigel2001(大宝)回复于 2006-02-04 16:26:57 得分 0

所以我的意思是,如何将这个已经分配的raw   memory还给系统。难道你所说的“new   异常在编译器会有默认的异常处理”便能释放所分配的raw   memory?  
  --------------------------------------------------  
  这点lz确实不用操心.  
   
   
  1.调用operator   new()分配sizeof(foo)大小的raw   memory;  
  --------------------------------------------------  
  如果出错的话,没有内存被分配,所以不用处理.  
   
   
  2.调用foo类的构造函数对1中分配的内存进行初始化。  
  --------------------------------------------------  
  如果出错的话,运行时系统会调用delete的.  
   
   
  直接判断指针是不是空就可以了  
  --------------------------------------------------  
  这种方法比较土,而且对于新标准来说是一种倒退.  
   
   
  一个常见的解决方案是提供   init   函数,把所有要求资源申请都集中到init   函数中。这样   constructor就不会抛出异常了。  
  --------------------------------------------------  
  事实上,catch到bad_alloc,是无法区分具体在第一步还是第二步发生了错误,这个解决方案就是强制bad_alloc只有在第一步才能抛出,把constructor里面的语句(就使new的第二步)都搬到init函数里面去,保留一个空的constructor,这样第二步就是空的就不会出错了  
   
   
  总之,楼主多虑了,reclaim内存的事情,您就别殚精竭虑了.  
  当然要管理内存分配情况,包括重载new,delete等等要考虑的东西还是比较多的.Top

11 楼cpp_wq(天天C++)回复于 2006-02-04 16:38:36 得分 0

to   zmjsx(风向):  
   
      你的方法很有诱惑力,但是能不能给出源码,让大家参考参考。Top

12 楼cpp_wq(天天C++)回复于 2006-02-04 16:43:52 得分 0

to   rigel2001(大宝):  
   
  “  
  2.调用foo类的构造函数对1中分配的内存进行初始化。  
  --------------------------------------------------  
  如果出错的话,运行时系统会调用delete的.  
  ”  
   
  真是这样么?如果真是如此,那我真是多想了!但希望人兄给出此观点的可靠论据(别误会,我不是不相信你,只是想了解的多一些)Top

13 楼ox_thedarkness()回复于 2006-02-04 17:26:17 得分 0

阿哈,果然如   rigel2001(大宝)   所言呢,下面代码在VC7   /   DevC++4.9   下执行  
  都显示系统自动delete了之前分配给foo的内存呢  
   
  不晓得C++标准是如何规定的?  
   
  //////////////////////////////////////////////////////  
  #include   <iostream>  
  #include   <new>  
  #include   <cstdlib>  
   
  using   namespace   std;  
   
  void*   operator   new(   size_t   n   ){   //   正常的重载new  
  void*   p   =   malloc(   n   );  
  printf(   "new   (%d)   #%p\n",   n,   p   );  
  return   p;  
  }  
   
  void*   operator   new(   size_t   n,   bool   badAlloc   ){   //   new(true)调用这个版本的new,抛出bad_alloc  
  printf(   "new   (%d)   fail\n",   n   );  
  throw   bad_alloc();  
  }  
   
  void   operator   delete(   void*   p   ){  
  printf(   "delete   #%p\n",   p   );  
  free(   p   );  
  }  
   
  class   foo{  
  public:  
        foo():a(0)   {     pi   =   new(false)   int(3);     }        
  private:  
        int   a;  
        int   *pi;  
  };  
   
  int   main(){  
  foo   *pf   =   0;  
  try{  
  pf   =   new   foo();  
  }catch(...){}  
  delete   pf;  
  cin.get();  
  }Top

14 楼rigel2001(大宝)回复于 2006-02-05 15:24:38 得分 0

实际上,  
   
  C*   p   =   new   C;  
   
  这句话调用的是类似下面__new(基于new之上)的东西  
   
  void   __new()   throw   (bad_alloc)  
  {  
          C   *   p   =   reinterpret_cast<C*>   (new   char[size]);    
          try  
          {  
                new   (p)   C;    
          }  
          catch(...)    
          {  
                delete[]   p;    
                throw;    
          }  
  }  
  Top

15 楼rigel2001(大宝)回复于 2006-02-05 15:28:52 得分 0

真是这样么?  
  -----------  
  真是这样Top

16 楼lovedna(有间道)回复于 2006-02-05 18:18:48 得分 0

foo():a(0)   {   pi   =   new   int(3);}  
   
  问题出在这条语句中,  
   
  int(3)  
   
  楼主说这条语句出错是吧!     int   类是系统定义的,错误处理系统当然会处理,  
   
  如果推广到自定义类:  
   
  MyClass   (3)  
   
  出错的话,出错处理也只能在MyClass类中.  
   
  Top

17 楼xlsue(小林)回复于 2006-02-05 18:38:59 得分 0

foo   *pf   =   new   foo();  
  //在foo构造函数中发生异常,这里并不会发生momery   leak。因为new   operator中已经有个异常处理。。。Top

18 楼xlsue(小林)回复于 2006-02-05 18:49:28 得分 0

如大宝所说的,大宝挺好的,我天天用:)Top

19 楼ox_thedarkness()回复于 2006-02-05 21:54:54 得分 0

哦~~   原来如此~~  
  顶一个大宝~~Top

20 楼rigel2001(大宝)回复于 2006-02-05 22:32:49 得分 0

hehe~Top

相关问题

  • Memory Leak
  • leak memory???
  • 关于Memory Leak!?????
  • 关于memory leak问题
  • 使用CHtmlView后memory leak的问题
  • 举一个memory leak的例子
  • 各位大侠,哪有用于VC的检查memory leak的工具下载?
  • 请问在bcb下面如何自己添加内存泄漏(Memory Leak)的检测代码?
  • 大家遇到Memory Leak后怎么定位错误? 想请各位发表一下意见
  • 动态调用DLL时的HINSTANCE句柄是不是还应该释放。我用BoundsChecker检测时在这里报Memory Leak

关键词

  • c++
  • 函数
  • 内存
  • 编译器
  • 指针
  • 语句
  • 系统
  • 调用
  • pf
  • 异常

得分解答快速导航

  • 帖主:cpp_wq

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo