C++ 从未调用大小运算符delete[]

C++ 从未调用大小运算符delete[],c++,c++14,c++17,C++,C++14,C++17,我正在努力跟踪在我的开发中分配了多少内存。跟踪分配很容易,因为超负荷的void*操作符new(size\u t)和void*操作符new[](size\u t)允许跟踪分配了多少。 用C++ < C++ 14,< /p> 自C++14以来,有相应的void操作符delete(void*p,size\u t size)和void操作符delete[](void*p,size\u t size)应该允许准确地说明每次取消分配(不完整类型的删除除外,然后留给实现) 然而,尽管g++调用了第一个版本,其

我正在努力跟踪在我的开发中分配了多少内存。跟踪分配很容易,因为超负荷的
void*操作符new(size\u t)
void*操作符new[](size\u t)
允许跟踪分配了多少。 用C++ < C++ 14,< /p> 自C++14以来,有相应的
void操作符delete(void*p,size\u t size)
void操作符delete[](void*p,size\u t size)
应该允许准确地说明每次取消分配(不完整类型的删除除外,然后留给实现)

然而,尽管g++调用了第一个版本,其中调用了删除单个对象,但我还没有找到一个编译器调用第二个。以下是我的测试代码:

#include <iostream>
size_t currentAlloc;

void * operator new(size_t size)
{
    currentAlloc += size;
    std::cout << "1\n";
    return malloc(size);
}

void *operator new[](size_t size)
{
    std::cout << "3\n";
    currentAlloc += size;
    return malloc(size);
}

void operator delete(void *p) noexcept
{
    std::cout << "Unsized delete\n";
    free(p);
}

void operator delete(void*p, size_t size) noexcept
{
    std::cout << "Sized delete " << size << '\n';
    currentAlloc -= size;
    free(p);
}

void operator delete[](void *p) noexcept
{
    std::cout << "Unsized array delete\n";
    free(p);
}

void operator delete[](void*p, std::size_t size) noexcept
{
    std::cout << "Sized array delete " << size << '\n';
    currentAlloc -= size;
    free(p);
}

int main() {
    int *n1 = new int();
    delete n1;

    int *n2 = new int[10];
    delete[] n2;

    std::cout << "Still allocated: " << currentAlloc << std::endl;
}
#包括
尺寸和电流分配;
void*运算符新(大小\u t大小)
{
currentAlloc+=尺寸;
std::cout根据通常是可靠的,未指定在“删除不完整类型的对象以及非类和普通可破坏类类型的数组时”调用哪个版本(我的重点)


编译器似乎在默认情况下禁用了大小删除。

大小释放API的目的不是帮助您跟踪已分配或释放的内存量,而且无论如何也不能可靠地用于此目的。大小释放API的目的是提高支持大小释放的内存分配器的效率解除分配,因为它允许编译器在某些情况下调用大小解除分配方法,这意味着内存分配器在执行解除分配时不需要查找解除分配指针的大小。Andrei Alexandrescu在2015年CppCon关于API的讨论中对此进行了一些讨论

大多数内存分配器都提供了这样的API,允许您显式地查询分配器,以获取有关已分配或解除分配内存量的统计信息;我建议您阅读您正在使用的任何分配器的文档,以了解如何访问这些统计信息

<> P>您不能使用它来跟踪所有DeloPosits的总大小,一般来说,编译器并不总是知道开始删除的对象的大小。例如,考虑下面的代码:

char*foo(大小){
char*p=新字符[n];
//用p做一些事情,也许填上它
返回p;
}
空栏(字符*p){
删除[]p;
}
空隙率(大小单位){
char*p=foo(n字节);
巴(p);
}
在这种情况下,内存分配在一个位置,但在其他位置取消分配,有关分配大小的信息在取消分配站点丢失。此特定示例非常简单,因此如果两个函数位于附近,优化编译器可能会看穿此示例,但通常不能保证si将使用zed解除分配函数,这是编译器可以执行的操作


此外,即使使用
-std=c++14
或(更高的标准版本,如c++17或c++20)进行编译,Clang目前(截至2020年底)也无法启用大小交易;当前要将其添加到已使用大小的释放,您需要将
-fsized deallocation
添加到您的clang命令行。

您似乎假设
free(p);
中的
void操作符delete[](void*p)noexcept
不会释放整个数组。您使用
malloc()
free()的原因是什么
优先于
new()
delete()<弗兰>席奥伊德里乌斯,我不知道你在想什么?我没有对自由进行任何假设。我只是想知道我的代码在任何时间点上分配了多少内存。@米歇尔,你只在两个操作符中跟踪它。例如:代码>操作符删除(空洞*)
可能会释放内存,但您没有在那里跟踪它。
/Zc:SizedDelloc
在这里没有任何区别,MSDN中的关键引用是“当编译器无法确定要释放的对象的大小时,调用单参数版本”,编译器无法从原始指针轻松确定数组的大小。