C++ 内存泄漏

本文深入探讨了C++中内存泄漏的问题,通过示例代码解析了由于类型匹配不当导致析构函数未调用而产生的内存泄漏。强调了在释放内存时必须确保正确匹配分配和释放函数,以及避免空指针导致的错误。同时,提到了在处理结构化元素时,应先释放子内存再释放父节点。文章还提醒了程序员在使用 memset 和 malloc 或 calloc 分配内存时的注意事项。
摘要由CSDN通过智能技术生成

参考链接
里面的示例代码

typedef struct DATA_{
    DATA_(int size = 10){        
        pVoid = new char[nSize];
        this->size = size;    
    }
    virtual ~DATA_()    {
        if (pVoid){
            delete pVoid;        
        }    
    }
    int nSize;
    void *pVoid;
}DATA, *LPDATA;
struct STRUCT1{
    STRUCT1(int count){        
        pVoid = new DATA[count];
        this->count = count;
    }
    virtual ~STRUCT1(){
        if (pVoid){
            delete pVoid;        
        }    
    }
    int count;
    union    {
        void *pVoid;        
        LPDATA pData;   #这个未delete,所以产生内存泄漏 
    }
}
int main(int argc, char* argv[]){
    for( int i = 0; i < 1000; i++){
        void *p = new STRUCT1( 10 );
        delete p;    
    }
    return 0;
}

造成内存泄漏的原因
在上面这段代码中,STRUCT1中包含了若干个DATA结构,DATA结构又申请了默认为10byte大小的内存,并且内存在对象析构的时候会用delete回收。乍一看这个代码貌似不会泄露内存,其实不然,待我分析:

在C++中构造函数与析构函数的调用是由编译器完成的,其中构造函数的调用一般是在对象空间开辟完以后(栈对象或者堆对象都是一样的),将参数压栈,this指针(对象的起始地址)放入eax寄存器(不同的编译器做法可能不同),然后跳到构造函数去执行。而析构函数的调用则是当对象内存被回收的时候被调用(栈对象是当代码执行到变量可见域外之前调用, 堆对象是在delete语句的位置进行调用)。

然而编译器并是那么智能的可以理解coder的意图,析构函数的调用是根据当前delete的指针类型来确定的,而(下面)这段代码却没有提供类型, 这导致了DATA_的析构函数将不会被调用,内存泄漏就在所难免了。

避免出现内存泄漏的注意事项:

  1. 始终结合使用 memset 和 malloc分配内存,或始终使用 calloc。

  2. 每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对。

  3. 在对指针赋值前,要确保没有内存位置会变为孤立的。

  4. 每当释放结构化的元素(而该元素又包含指向动态分配的内存位置的指针)时,都应首先遍历子内存位置并从那里开始释放,然后再遍历回父节点。

  5. 始终正确处理返回动态分配的内存引用的函数返回值。

  6. 每个 malloc 都要有一个对应的 free。

  7. 确保您不是在访问空指针。
    那么存在空指针会出现内存泄漏吗,是不会的,因为空指针本身就没有给他分配内存空间,充其量只是在栈上占用了四个字节的变量空间,一旦脱离域之后自然消失了。
    像如下面这个例子


#include<bits/stdc++.h>
using namespace std;
struct A{
    int b;
    A(){
        cout<<"rrrrrrrrrr"<<endl;
    }
    ~A(){
        cout<<"dddd"<<endl;
    }
};
struct B{
    A* p;
    ~B(){
        cout<<"ooooooooo"<<endl;
        delete p;
        cout<<"mmmmmmmmm"<<endl;
    }
};

int main(){
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);
    B *e;
    delete e;
    return 0;
}

A里面的b都没有初始化,压根就是个空指针,delete空指针不会产生任何操作,而且空指针本身也不会申请得到空间,但是会出错。
运行结果如下:
在这里插入图片描述

示例3

#include<bits/stdc++.h>
#include<string>
using namespace std;
unordered_map<string,int>info;
unordered_map<string,string>question;
typedef long long ll;
void fun(char *p){
    p = (char*)malloc(sizeof(char)*10);
}
int main(){
    //freopen("in.txt","r",stdin);
    for(int i = 0;i<1000000000000000;i++){
        char *p = NULL;
        fun(p);
        if(p == NULL){
            cout<<"dddd"<<endl;
        }
        free(p);
    }
    return 0;
}

这样也会造成内存泄漏,因为fun函数中的p变量指向的空间没有被析构掉,free的一直是个空指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值