c++ - 我将如何使用大小运算符 delete/delete[] 以及为什么它们更好?

标签 c++ c++14 delete-operator

C++14 介绍 "sized" versions of operator delete ,即

void operator delete( void* ptr, std::size_t sz );

void operator delete[]( void* ptr, std::size_t sz );

通读N3536 ,似乎引入这些运算符是为了提高性能。我知道 operator new 使用的典型分配器在某处“存储”大容量内存的大小,这就是典型的 operator delete 如何“知道”返回多少内存免费商店。

但我不确定为什么 operator delete 的“大小”版本会在性能方面有所帮助。唯一可以加快速度的是关于控制 block 大小的少读操作。这真的是唯一的优势吗?

二、数组版本怎么处理? AFAIK,分配数组的大小不仅仅是 sizeof(type)*number_elements,而是可能分配了一些额外的字节,因为实现可能使用这些字节作为控制字节。在这种情况下,我应该将什么“大小”传递给 operator delete[]?能否提供一个简短的使用示例?

最佳答案

先处理你的第二个问题:

If present, the std::size_t size argument must equal the size argument passed to the allocation function that returned ptr.

因此,任何可能分配的额外空间都是运行时库的责任,而不是客户端代码。

第一个问题比较难回答。主要想法是(或至少看起来是) block 的大小通常不会存储在 block 本身旁边。在大多数情况下, block 的大小被写入,并且在 block 被释放之前永远不会再次写入。为避免在使用 block 时数据污染缓存,可以单独保存。然后当你去释放 block 时,大小会经常被分页到磁盘,所以读回来很慢。

完全避免显式存储每个 block 的大小也很常见。分配器通常会为不同大小的 block (例如,从 16 到大约几千字节左右的 2 的幂)设置单独的池。它将为每个池从操作系统分配一个(相当)大块,然后将该大块的一部分分配给用户。当你传回一个地址时,它基本上会通过不同大小的池来搜索该地址,以找到它来自哪个池。如果你有很多池并且每个池中有很多 block ,那可能会相对较慢。

这里的想法是避免这两种可能性。在典型情况下,无论如何,您的分配/解除分配或多或少都与堆栈相关,并且当它们是您分配的大小时,可能会在局部变量中。当您解除分配时,您通常会处于(或至少接近)与分配位置相同的堆栈级别,因此相同的局部变量将很容易获得,并且可能不会被分页到磁盘(或类似的东西),因为附近存储的其他变量也在使用中。对于非数组形式,对 ::operator new 的调用通常源自 new 表达式,而对 ::operator delete 的调用> 来自匹配的 delete expression。在这种情况下,为构造/销毁对象而生成的代码仅根据正在创建/销毁的对象类型“知道”它将请求(和销毁)的大小。

关于c++ - 我将如何使用大小运算符 delete/delete[] 以及为什么它们更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34407032/

相关文章:

c++ - 洪水填充C++

c++ - 具有低冲突率的 32 位整数的快速字符串散列算法

c++ - 为什么有变异的 Boost.Range 算法的 const 重载?

c++ - 调用由指针非静态初始化的类方法

C++删除,但不只是类型

c++ - delete p 在析构函数中执行

c++ - 在 SFML 2.4 中使用碰撞检测来增加游戏分数的问题

c++ - 跨平台毫秒计时器持续超过 49 天?

c++ - 为什么 char{} 和 char() 用作 char* 参数的临时变量?

c++ - 是否有必要在数组收缩时删除元素?