C++项目总结三之内存泄漏

这篇文章简单讨论下c++中的内存泄漏问题。在本例中需要用到第一篇中关于内存泄漏检测的头文件,用来辅助检测程序中的内存泄漏情况。

1.只分配不释放

程序1:

#include <stdio.h>
#include <string.h>
#include "common.h"
int main()
{
    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
    int *p = (int*)malloc(sizeof(int));
    int *q = new int;
    return 0;
}

上面程序中分别使用malloc和new分配了两个int型内存。但没有对动态分配的内存进行释放。程序运行结束,在vs2008输出窗口输出如下信息
这里写图片描述

2.分支引起的内存未释放

程序2:

#include <stdio.h>
#include <string.h>
#include "common.h"
void func(int flag)
{
    int *p = new int;
    if(flag)
    {
        return;
    }
    delete p;
}
int main()
{
    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
    func(1);
    return 0;
}

上面的程序中,在func中我们动态分配的内存空间,在程序最后使用delete p;释放了内存。但上面程序运行结束后会在vs2008输出窗口提示我们func中的int *p = new int;分配的空间没有释放。简单分析下是由于程序中判断了参数flag的值,如果为真,程序就直接返回。后面的释放代码就无法执行了。其实上面的func代码比较简单,所以还是比较容易能找到原因。但在实际开发中功能比较复杂,判断复杂,有时并不太容易发现内存泄漏。并且有时内存泄漏的情况只有在特定条件下才会发生,如上面的程序。如果func传的参数值一直都是0 ,那么内存泄漏永远都不会发生。

3.异常情况引起的内存泄漏

程序3:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include "common.h"
void func(int iNum)
{
    int iVal = 100;
    int *p = new int;
    if(iNum==0)
    {
        throw std::exception("除数为0");
    }
    *p = iVal/iNum;
    delete p;
}
int main()
{
    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
    try
    {
        func(0);
    }
    catch(...)
    {

    }
    return 0;
}

上面的程序执行完成后会提示第8行分配的内存没有释放。这是因为我们在func函数判断当iNum==0时,抛出一个异常,这时程序会返回到main函数中进行处理,func最后两句就不会再被执行,从而导致内存泄漏。上面的程序我们完全可以在判断iNum==0的时候执行释放语句。程序这么只是简单的模拟,因为在实际开发中,我们不可能判断出所有的异常情况。对于比较有可能发生异常的函数内,我们尽量不要动态分配内存空间;在必须要动态分配内存的情况下,如果处理的是字符串,那么使用stl string或第三方开源c++字符串处理类的对象来实现;如果是为对象分配动态空间,使用智能指针来管理对象指针,因为C++保证在发生异常时,局部对象的析构函数一定会被调用。

4.继承引起的内存泄漏

在我做的保密检查工具中需要对ntfs及fat32文件系统中被删除的文件进行恢复。程序大致结构如下:
程序4:

class CFileSystem
{

};
class CFat32FileSystem:public CFileSystem
{

};
class CNtfsFileSystem:public CFileSystem
{
public:
    CNtfsFileSystem()
    {
        m_bitmap = new(xxxx);
    }
    ~CNtfsFileSystem()
    {
        delete m_bitmap;
    }
private:
    char *m_bitmap;
};

ntfs中的m_bitmap是用于记录分区中哪些扇区已被使用,哪些扇区是空闲的。该功能的使用大致如下:

CFileSystem *fileSystem = new CNtfsFileSystem;
delete fileSystem;

父类指针对象指向子类,这样无论子类是ntfs或者fat32。操作接口都是统一的。使用完后删除父类指针所指对象。后面在测试过中发现使用该功能,程序的内存会一直不停增长;后面分析发现虽然调用了delete fileSystem;但并没有调用CNtfsFileSystem的析构函数。这是由于我们没有把基类CFileSystem的析构函数定义成函数,这样执行delete语句只调用了父类的析构函数,没有调用子类CNtfsSystem的析构函数;造成了子类m_bitmap分配的空间没有释放。所以在编写一个类的时候,除非我们确定该类不会被继承,否则最好将该类的析构函数定义成虚函数。

5.指针类型转换引起的内存泄漏

#include <stdio.h>
#include <string.h>
#include "common.h"
using namespace std;
class A
{
public:
    A(){p = new char[1024];}
    ~A(){delete p;}
private:
    char *p ;
};
int main()
{
    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
    void *p = new A;
    delete p;
    return 0;
}

上面的程序定义了一个类A,在A的无参构造函数中给成员变量p动态分配了1024字节。在main函数中使用new创建一个A的对象,p指向新创建的对象。上面程序运行完成后却提示我们程序中有内存泄露。如下图
这里写图片描述
看下上面的main函数中,将p定义成了void*型,这样p可以指向任意的指针类型;执行delete p语句首先删除p所分配的空间,然后p是void *型,所以不会调用p所指向的真实类型的析构函数。上面的程序释放了分配类A的对象所占用空间,但是对于类A对象的成员在构造时动态分配的内存没有释放。从而产生内存泄漏。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值