内存泄漏专题(8)hook之C++运算符重载

简介: 内存泄漏专题(8)hook之C++运算符重载

C++主要是针对new/delete运算符进行重载 ,思路和上述hook malloc函数一样,我们可以定义一个MemCheck类,该类用来存储内存信息,包括内存的地址,大小。如果愿意的话,还可以存储调用的位置,这里为了简化处理,就不演示了。在调用 new运算符时,我们将申请内存的相关信息存入MemCheck中的一个map中,它的key是内存地址,value是内存大小。在调用delete时,将该内存地址从map中删除掉。(此处未判断double free的问题,可以考虑下如何去做?)有兴趣的话也可以考虑一下new[]delete[]的重载实现。

我们定义一个全局静态的MemCheck类实例,这样该实例对象的析构将会在main函数结束后才会进行,因此,我们只需要在析构函数中判断一下,map中是否还有没有元素存在,就知道还有没有内存泄漏了。将其打印出来即可。

完整代码示例如下:

//new.cpp
#include <iostream>
#include <malloc.h>
#include <memory>
#include <map>
bool new_enabled = true;
class MemCheck
{
private:
    std::map<void*, size_t> MemInfo; //key 为申请内存的地址, value为申请内存的大小
public:
    void Allocation(void *p, size_t size){
        //申请内存时将内存信息放入map
        new_enabled = false;
        MemInfo[p] = size;
        new_enabled = true;
    }
    void Freed(void *p) {
        //释放内存时将内存信息从map中移除
        MemInfo.erase(p);
    }
    ~ MemCheck(){
        std::cout << "Memory Not Freed:\n";
        std::map<void *, size_t>::iterator it = MemInfo.begin();
        while (it != MemInfo.end()) {
            std::cout << "\t[" << it->first << "] " << it->second << " bytes\n";
            it++;
        }
    }
};
static MemCheck mcheck;
void *operator new(size_t size)
{
    if (new_enabled) {
        void *p = malloc(size);
        mcheck.Allocation(p, size);
        return p;
    } else {
        return malloc(size);
    }
}
void operator delete(void *p) {
    mcheck.Freed(p);
    free(p);
}
struct Object {
    int x, y, z;
};
void test(){
    std::string str = "hello";
    Object *obj = new Object;
    std::unique_ptr<Object> obj2(new Object());
    //delete obj;
}
int main(void){
    test();
    int *pInt = new int;
    std::unique_ptr<int> p(new int);
    return 0;
}

以上代码,在test函数中,首先string的内存管理是交由编译器处理的,虽然程序员无需手动管理,但实际上也调用了newdeleteobj对象只有申请,没有释放,obj2是智能指针,其内存的生命周期由编译器进行管理,无需手动释放,在test函数结束时会自动释放掉。

main函数中,pInt的内存只有申请,没有释放,p是智能指针,在main函数结束时会自动释放。因此,该段代码有两处内存泄漏,分别为指针pIntobj,我们运行该段代码:

[root@ck08 memleak]# g++ new.cpp -std=c++11 -g
[root@ck08 memleak]# ./a.out 
Memory Not Freed:
        [0x7c5080] 12 bytes
        [0x7c50e0] 4 bytes

可以看到,确实打印出了两处内存泄漏,第一处是0x7c5080,该地址是obj的地址,第二处是0x7c50e0,正是pInt的地址。而指针p即使是在main函数结束时才被释放,但MemCheck仍然能够感知到其内存被释放了。


本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对C/C++课程感兴趣的读者,可以点击链接,查看详细的服务:C/C++Linux服务器开发/高级架构师

目录
相关文章
|
3月前
|
存储 编译器 C语言
内存管理【C++】
内存管理【C++】
|
8天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
27 4
|
1月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
156 1
|
1月前
|
存储 编译器 C++
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作(二)
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作
|
2月前
|
安全 C++
超级好用的C++实用库之环形内存池
超级好用的C++实用库之环形内存池
45 5
|
1月前
|
存储 编译器 C++
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作(三)
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作
|
1月前
|
存储 编译器 C++
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作(一)
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作
|
2月前
|
C++
超级好用的C++实用库之动态内存池
超级好用的C++实用库之动态内存池
29 0
|
2月前
|
C++
C++(十五) 运算符重载
C++中的运算符重载允许对已有运算符的功能进行重新定义,从而扩展语言功能、简化代码并提升效率。重载遵循特定语法,如 `friend 类名 operator 运算符(参数)`。重载时需注意不可新增或改变运算符数量、语义、优先级、结合性和返回类型。常见示例包括双目运算符 `+=` 和单目运算符 `-` 及 `++`。输入输出流运算符 `&lt;&lt;` 和 `&gt;&gt;` 也可重载。部分运算符只能作为成员函数重载。
|
4月前
|
NoSQL Redis C++
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难