内存泄漏专题(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服务器开发/高级架构师

目录
相关文章
|
17天前
|
存储 编译器 C语言
内存管理【C++】
内存管理【C++】
35 1
|
3月前
|
存储 架构师 NoSQL
一文带你走进C++【内存泄漏】
后记 遇到这样一个问题,其实还挺有趣的,虽然是一个小点,但是梳理了一个比较完整的思考过程,希望能对小伙伴们解决相关问题带来参考和想法。
50 4
|
3月前
|
编译器 C++
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
37 1
|
4月前
|
程序员 编译器 C++
C++中的运算符重载(Operator Overloading)
C++中的运算符重载(Operator Overloading)
39 1
|
10天前
|
C++
C++(十五) 运算符重载
C++中的运算符重载允许对已有运算符的功能进行重新定义,从而扩展语言功能、简化代码并提升效率。重载遵循特定语法,如 `friend 类名 operator 运算符(参数)`。重载时需注意不可新增或改变运算符数量、语义、优先级、结合性和返回类型。常见示例包括双目运算符 `+=` 和单目运算符 `-` 及 `++`。输入输出流运算符 `&lt;&lt;` 和 `&gt;&gt;` 也可重载。部分运算符只能作为成员函数重载。
|
2月前
|
NoSQL Redis C++
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
|
3月前
|
存储 编译器 C++
【C++】:拷贝构造函数和赋值运算符重载
【C++】:拷贝构造函数和赋值运算符重载
22 1
|
3月前
|
C++ 索引
C++核心技术要点《运算符重载》
C++核心技术要点《运算符重载》
45 2
|
2月前
|
自然语言处理 程序员 C++
C++基础知识(五:运算符重载)
运算符重载是C++中的一项强大特性,它允许程序员为自定义类型(如类或结构体)重新定义标准运算符的行为,使得这些运算符能够适用于自定义类型的操作。这样做可以增强代码的可读性和表达力,使得代码更接近自然语言,同时保持了面向对象编程的封装性。
|
2月前
|
Java 程序员 C++