为内存跟踪器重载delete[]运算符

3
为了跟踪内存分配,我一直在尝试重载C++中标量和数组版本的newdelete运算符。然而,delete[]的重载不起作用。我一直在尝试理解cppreference上的文档(https://en.cppreference.com/w/cpp/memory/new/operator_delete),但无法理解。我认为我对重载#5感兴趣,它是以下内容,但可能是错误的。 void operator delete ( void* ptr, std::size_t sz ) noexcept; 这是我目前用来测试我的想法的程序,以及我编写的所有函数。 请注意,我对一个能够处理内置类型和我创建的任何类/结构的内存分配器感兴趣。
#include<iostream>

// global variable
std::size_t g_allocatedMemory{};

// =======================================================================
// global overload for new
void* operator new(std::size_t size)
{
    g_allocatedMemory += size;
    
    std::cout << "Allocating " << size << " bytes\n";
    std::cout << "Current allocation = " << g_allocatedMemory << " bytes\n\n";

    return malloc(size);
}

// global overload for delete
void operator delete(void* memory, std::size_t size)
{
    g_allocatedMemory -= size;

    std::cout << "Freeing " << size << " bytes\n";
    std::cout << "Current allocation = " << g_allocatedMemory << " bytes\n\n";
    
    free(memory);
}

// =======================================================================

// global overload for new[]
void* operator new[](std::size_t size)
{
    g_allocatedMemory += size;
    
    std::cout << "Allocating " << size << " bytes\n";
    std::cout << "Current allocation = " << g_allocatedMemory << " bytes\n\n";

    return malloc(size);
}

// global overload for delete[]
void operator delete[](void* memory, std::size_t size)
{    
    g_allocatedMemory -= size;

    std::cout << "Freeing " ;//<< size << " bytes\n";
    std::cout << "Current allocation = " << g_allocatedMemory << " bytes\n\n";
    
    free(memory);
}

// =======================================================================

int main()
{
    int* p{ new int[5] };

    delete[] p;

    return 0;
}

我也尝试过使用C++17,但没有成功。
程序没有使用我提供的delete[]的重载。所以当我在main()中执行delete[] p时,屏幕上只会打印出int* p{ new int[5] };的输出,而没有任何来自delete[] p;的输出。
Allocating 20 bytes
Current allocation = 20 bytes

这是我编译代码的方式。
g++ -pedantic-errors -Wall -Weffc++ -Wextra -Wconversion -Wsign-conversion -std=c++14 .\leak.cpp

1
在我的另一个平台上,delete[] p; 调用的是 void operator delete[](void* memory) noexcept,但你没有提供这个替代的全局删除函数。这与 https://en.cppreference.com/w/cpp/memory/new/operator_delete 一致。我建议你替换 newdelete,而不是 mallocfree - undefined
1
@George 没错,但无论如何,这是不可能的。即使一个实现使用了 std::mallocstd::free,重新定义(覆盖)它们将违反唯一定义规则。(而重载它们也是无用的,因为新的重载显然不是被调用的那些)。 - undefined
不要忘记关于放置new。 - undefined
@Caleth 对的。说得好。 - undefined
@JesperJuhl 尽管 new(nothrow) 显然是“new 表达式的放置版本”,这样命名可能是因为语法规则的命名。 - undefined
显示剩余5条评论
1个回答

2
你必须提供一个operator delete[](void *ptr) noexcept函数。
请注意,当替换带有大小参数的版本时,标准要求替换非大小版本。
只需添加以下代码即可使用重载:
// global overload for delete[]
void operator delete[](void* memory)
{     
    std::cout << "test" << std::endl;
}

您使用这个额外的重载后,代码将输出以下内容:
Allocating 20 bytes
Current allocation = 20 bytes

test

嗨,我假设你提到的过载将是程序中的第五个功能(不包括上面显示的main())。问题是,我没有打印出被释放的内存量。此外,没有了size参数,我无法更新g_allocatedMemory,这意味着我无法跟踪程序当前在堆上分配的净内存。另外,我假设在void operator delete[](void* memory)的函数体中,我还需要添加语句free(memory),对吗? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接