怎么有效的防止内存泄漏

http://blog.csdn.net/couhujia/article/details/8474905

C++中如何防止内存泄漏(来自百度搜索)

1.尽量不去手动分配内存。比如,我一般不使用数组,而使用STL的vector.
2.如果需要手动分配数组,尽量使用STL中的分配方式,或者使用STL和BOOST中的智能指针。
http://www.cppblog.com/wanghaiguang/archive/2013/05/02/199909.aspx
2. 对于C和C++这种没有Garbage Collection 的语言来讲,我们主要关注两种类型的内存泄漏:

   堆内存泄漏(Heap leak)。对内存指的是程序运行中根据需要分配通过malloc,realloc new等从堆中分配的一块内存,再是完成后必须通过调用对应的 free或者delete 删掉。如果程序的设计的错误导致这部分内存没有被释放,那么此后这块内存将不会被使用,就会产生Heap Leak. 

  系统资源泄露(Resource Leak).主要指程序使用系统分配的资源比如 Bitmap,handle ,SOCKET等没有使用相应的函数释放掉,导致系统资源的浪费,严重可导致系统效能降低,系统运行不稳定。 

首先说说标题可能取得有些大,但是可以理解为编程过程中有效的防止写的代码中有内存泄漏。好了废话不多说了,首先看下面一段代码。

[cpp] view plaincopy

  1. class Image  
  2. {  
  3. public:  
  4.         Image(const std::string& imgFileName);  
  5.         ...  
  6. }  
  7. class Voice  
  8. {  
  9. public:  
  10.         Voice(const std::string& vFileName);  
  11.         ...  
  12. }  
  13. class People  
  14. {  
  15. public:  
  16.             People(const std::string& n,const int& a,const int& h,const std::stirng& imgFileName,const std::string& vFileName);  
  17.             ~People( );  
  18. private:  
  19.             string name;  
  20. int       age;  
  21. int       height;  
  22.             Image *pImg;          //图像
  23.             Voice   *pVoi;          //声音
  24. };  
  25. People::People( const std::string& n,const int& a,const int& h,const std::stirng& imgFileName,const std::string& vFileName )  
  26. :name(n),age(a),height(h),pImg(0),pVoi(0)  
  27. {  
  28. if(imgFileName != "")  
  29.         {  
  30.             pImg = new Image( imgFileName ) ;  
  31.         }  
  32. if(vFileName != " ")  
  33.         {  
  34.             pVoi = new Voice ( vFileName );  
  35.         }  
  36. }  
  37. People::~People( )  
  38. {  
  39. delete pImg;  
  40. delete pVoi;  
  41. }  

上面代码粗略看似没有问题,但是有没有想到如果People构造函数出错(内存不足,无法分配内存)怎么办?其结果可以预见,就是一个异常抛出来。但是我们仔细想想此时如果已经构造了Image类对象,而在构造Voice类对象时抛出的错误,这个情况会怎么办?程序会因为异常而停止,后面代码不会执行,那么pImg指针所指向的内存就不会得到正确的释放,那么内存就泄漏了。情况如下面代码:

[cpp] view plaincopy

  1. ...  
  2. People *p =NULL;  
  3. try{  
  4.     p=new People("test",20,170,".../images/image01.jpg","../voices/voice01.dat");  
  5.     ...  
  6. catch( ... ){  
  7. delete p;  
  8. throw;  
  9.  }  
  10. delete p;  
  11. }  

仔细想想 new People("test",20,170,".../images/image01.jpg","../voices/voice01.dat")里,如果最后为Image分配的内存被丢失,因为new操作没有成功完成,程序不会p进行赋值操作。所以catch中是没有任何操作的,已被分配的内存就丢失了。

因为对象在构造中抛出异常后C++不负责清除对象,所以我们需要重新设计构造函数让它们在运到异常的时候自己能清除所占用的内存。

[cpp] view plaincopy

  1. People::People( const std::string& n,const int& a,const int& h,const std::stirng& imgFileName,const std::string& vFileName )  
  2. :name(n),age(a),height(h),pImg(0),pVoi(0)  
  3. {  
  4. try {  
  5. if(imgFileName != "")  
  6.         {  
  7.             pImg = new Image( imgFileName ) ;  
  8.         }  
  9. if(vFileName != " ")  
  10.         {  
  11.             pVoi = new Voice ( vFileName );  
  12.         }  
  13.     }  
  14. catch( ...) {  
  15. delete pImg ;  
  16. delete pVoi;  
  17. throw ;  
  18. }  

这样就行了,解决上面的情况。让成员变量成为const指针,这样设计也合理,避免指针无意被改变。

[cpp] view plaincopy

  1. Image * const pImg;          //图像
  2. Voice   * const pVoi;        //声音

那么这样就只能用成员初始化列表为指针初始化,就没有其他地方可以给const指针赋值了。

[cpp] view plaincopy

  1. People::People( const std::string& n,const int& a,const int& h,const std::stirng& imgFileName,const std::string& vFileName )  
  2. :name(n),age(a),height(h),  
  3. pImg( imgFileName !="" ? new Image( imgFileName ) : 0 ),  
  4. pVoi( vFileName != "" ? new Voice( vFileName ) : 0)  
  5. {}  

如果这样就重新回到上面所遇到的问题,即构造过程中抛出异常,指针可能无法正确的释放所占内存。那么我们可以进一步对代码进行改进,如下:

[cpp] view plaincopy

  1. People::People( const std::string& n,const int& a,const int& h,const std::stirng& imgFileName,const std::string& vFileName )  
  2. :name(n),age(a),height(h),  
  3. pImg( initImage( imgFileName ) ),  
  4. pVoi(  initVoice( vFileName ) )  
  5. {}  
  6. Image* People::initImage(const string& imgFileName)   
  7. {  
  8. if(imgFileName !="") return new Image(imgFileName);  
  9. else return 0;  
  10. }  
  11. Voice* People::initVoice(const string& vFileName)  
  12. {  
  13. try
  14.     {  
  15. if(vFileName !="")return new Voice(vFileName)  
  16.         esle return 0;  
  17.     }  
  18. catch(... )  
  19.     {  
  20. delete pImg;  
  21. throw;  
  22.     }  
  23. }  

这样在调用构建Voice对象中加入try...catch...用于释放pImg所占用的内存空间。其实有一个比其更简单的方法就是使用智能指针。

[cpp] view plaincopy

  1. const auto_ptr<Image> pImg;  
  2. const auto_ptr<Voice>  pVoi;  
  3. People::People( const std::string& n,const int& a,const int& h,const std::stirng& imgFileName,const std::string& vFileName )  
  4. :name(n),age(a),height(h),  
  5. pImg( imgFileName !="" ? new Image( imgFileName ) : 0 ),  
  6. pVoi( vFileName != "" ? new Voice( vFileName ) : 0)  
  7. {}  

那么问题就算解决了,因为当其中有一个创建失败,离开函数的时候,智能指针会自动删除已经创建的空间,防止内存泄漏了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏iOS技术杂谈

iOS runtime探究(五): 从runtime开始深入weak实现机理你要知道的runtime都在这里

你要知道的runtime都在这里 转载请注明出处 https://cloud.tencent.com/developer/user/1605429 本文主要讲解...

36360
来自专栏微服务生态

由学习《软件设计重构》所想到的代码review(二)

我们接第一篇来继续说明在代码review中,有哪些属于“层次结构”中的坏味道。 第一篇链接如下:http://www.jianshu.com/p/07dbf6...

9220
来自专栏大史住在大前端

野生前端的数据结构基础练习(2)——队列

循环队列书中并没有提及,它是一种特殊的队列。简单理解就是将基本队列只当做存储结构,而使用front和rear两个指针分别代表队列的头和尾,实际对外表现的队列是f...

22330
来自专栏开源优测

[接口测试_B] 03 Pytest断言处理_assert和异常断言

Pytest的断言方式及应用场景 使用assert语句 断言预期的异常 断言预期的告警 利用上下文信息进行断言 自定义断言方式 使用assert语句进行断言...

453110
来自专栏企鹅号快讯

Python模块知识4:序列化Json/pickle

序列化与反序列化 序列化:把Python的基本数据类型转为字符串 反序列化:把字符串转为Python的基本数据类型 Python中用于序列化的两个模块: jso...

23090
来自专栏一个爱吃西瓜的程序员

每天学习一点儿算法--广度优先搜索

广度优先搜索(BFS)是我们学的第一种图算法,它可以让你找出两样东西之间的最短距离。 这里提到了一个新的概念:图, 那什么是图呢? 图简介 图用于模拟不同的东...

32540
来自专栏用户2442861的专栏

数据库系统——B+树索引

http://blog.csdn.net/cjfeii/article/details/10858721

50210
来自专栏Vamei实验室

纸上谈兵: 哈希表 (hash table)

HASH 哈希表(hash table)是从一个集合A到另一个集合B的映射(mapping)。映射是一种对应关系,而且集合A的某个元素只能对应集合B中的一个元素...

226100
来自专栏Golang语言社区

使用 Go 语言学会 Tensorflow

Tensorflow 并不是一个专门用于机器学习的库,相反的,它是一个通用的用于图计算的库。它的核心部分是用 C++ 实现的,同时还有其它语言的接口库。Go 语...

50920
来自专栏不会写文章的程序员不是好厨师

浅析HystrixRollingNumber(用于qps计数的数据结构)

考虑到一种需求场景,我们需要统计系统qps、每秒平均错误率等。qps表示每秒的请求数目,能想到的最简单的方法就是统计一定时间内的请求总数然后除以总统计时间,所以...

32920

扫码关注云+社区

领取腾讯云代金券