You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重载operator delete[]与析构函数的关联问题解析

重载数组new/delete时的内存追踪异常问题解答

我实现了一个TvectorPublic类,通过重载operator new[]和operator delete[]来追踪内存分配与释放情况:

class TvectorPublic
{
public:
    int x, y, z;
    
    TvectorPublic(int x_1 = 0,int y_1 = 0,int z_1 = 0) : x(x_1),y(y_1),z(z_1)
    {}

    void m_DoubleValue()
    {
        x *= 2;
        y *= 2;
        z *= 2;
    }

    void m_AddingValue(int value)
    {
        x += value;
        y += value;
        z += value;
    }

    void* operator new[](size_t size_1)
    {
        std::cout << "Creating TvectorPublic object.\n";
        std::cout << "Reserving memory: " << size_1 << " bytes.\n";

        return (::new char[size_1]);
    }

    void operator delete[](void* pointer, size_t size_1) noexcept
    {
        if (pointer)
        {
                std::cout << "\nDeleting TvectorPublic object.\n";
            std::cout << "Freeing memory: " << size_1 << " bytes.\n";

            ::delete[] static_cast<char*>(pointer);
        }
    }
};

在main函数中创建该类的对象数组:

TvectorPublic* pointer_1 = new TvectorPublic[3];
std::cout << "\n";

for (int i = 0; i < 3; i++)
{
    std::cout << pointer_1[i] << "\n";
}
std::cout << "\n";

delete[] pointer_1;

运行后发现:分配的内存为36字节,但仅释放了12字节;当为类添加如下空析构函数后:

~TvectorPublic()
{
    std::cout << "DestructorCalled\n";
}

分配和释放的内存均变为40字节,异常消失。以下是针对问题的解答:


1. 未定义析构函数时为何出现内存泄漏?编译器为何不生成默认析构函数?

先澄清一个误区:编译器会生成默认析构函数,这里的问题和析构函数是否生成无关,而是数组delete[]调用重载函数时的参数匹配问题。

当类里只有内置类型(比如这里的int),没有用户定义的析构函数时,编译器认为不需要逐个调用对象的析构函数——反正析构也不会做任何操作。这时候new[]分配的就是3个对象的总大小:3 * sizeof(TvectorPublic) = 3*12=36字节。但调用delete[]时,编译器没法正确把总内存大小传递给你重载的带size_t参数的operator delete[],它可能只传递了单个对象的大小12字节,导致你追踪到的释放大小是12,但实际上全局的delete[]还是释放了整个36字节的内存,并没有真的泄漏,只是追踪显示的数值错了。

2. 添加空析构函数后,内存占用为何增加4字节?

当类有用户定义的析构函数时,new[]必须额外分配一块内存来存数组元素的个数(32位系统下是4字节,64位是8字节)——因为delete[]需要知道要调用多少次析构函数。所以总内存大小就变成了:4字节计数 + 3*12字节对象 = 40字节,这就是你看到内存多了4字节的原因。

3. 为何只有添加析构函数后,全部内存才会被释放?(创建单个对象时无此异常)

单个对象的new/delete不需要记录元素个数,所以不管有没有析构函数,operator new/delete拿到的参数都是单个对象的正确大小,不会出问题。

而数组场景下:

  • 没有用户析构函数时,编译器不需要那个计数头,new[]直接分配36字节,但delete[]调用你重载的带size_t参数的版本时,没法正确传递总内存大小,只能传单个对象的12字节,导致你追踪到的释放数值不对,但实际内存没漏。
  • 有用户析构函数时,new[]分配了带计数头的40字节,delete[]通过计数头能算出总内存大小,把40正确传递给你的重载函数,所以追踪显示的分配和释放大小一致,看起来就像“全部内存被释放”了。

另外补充:C++标准里,带size_t参数的operator delete[],只有编译器能确定内存块大小时才会传递正确的数值。有析构函数的数组场景,编译器能通过计数头拿到总大小;没析构函数的数组场景,编译器没法准确获取,就传递了错误的size值。


内容的提问来源于stack exchange,提问作者Jakub

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 00:52:49