关于delete、delete[]、operator delete()等[重复]

Posted

技术标签:

【中文标题】关于delete、delete[]、operator delete()等[重复]【英文标题】:About delete, delete[], operator delete(), etc [duplicate] 【发布时间】:2011-04-07 05:52:50 【问题描述】:

可能的重复:How does delete[] “know” the size of the operand array?( POD )freeing memory : is delete[] equal to delete ?

据我了解,以下

class A ;
A* a = new A;
//
delete A;

将首先调用operator new()(全局调用,或A 提供的专用调用)来分配正确的内存量,然后调用A 的构造函数。当delete 是调用,就是会先调用A的析构函数,然后调用operator delete()去释放“适量的内存”。

正如我在 TC++PL 中所读到的,这个“正确的内存量”是这样确定的:

要释放由 new 分配的空间,delete 和 delete[] 必须能够确定分配的对象的大小。这意味着使用 new 的标准实现分配的对象将比静态对象占用更多的空间。通常,用一个词来表示对象的大小。

这是有道理的。但是这个词存储在哪里可以被delete 访问?就在新指针指向的地址之前?这样delete可以通过访问a-sizeof<void*>获取要删除的大小?

你能澄清一下吗?

我认为这个问题的答案可能有助于我理解 delete [] 的工作原理。我了解new [] 将如何工作,delete [] 将首先调用“数组的所有对象”的析构函数并释放所有这些内存......

但是delete []怎么知道数组的大小呢?

感谢您的帮助!

【问题讨论】:

我认为这取决于实现,但更多开明的人肯定会更具体。 相关:( POD )freeing memory : is delete[] equal to delete ? 【参考方案1】:

这一切都取决于实现。

大多数运行时确实会在返回内存 ((BYTE *)p-sizeof(size_t)) 之前存储内存大小,但还有其他选择。在我自己的内存管理器中(是的,我写了这种东西),在返回的内存之前,我有一个更复杂的数据结构(使用指向链表、校验和的指针)。实际上由内存管理器决定在哪里存储这些信息。

除了分配内存的大小,new[] 还将存储实例的数量,以便知道要调用多少个析构函数。这通常超出了内存管理器的范围,通常由 C++ 运行时/编译器本身处理。但同样,这个数量的实例存储在哪里取决于编译器,尽管实际上我希望它存储在返回的内存之前(以及内存管理器存储的任何数据之后。

编辑: 以下小实用程序显示了分配内存之前的内存布局:

#include <iostream>

typedef unsigned char Byte;

class X
   
   public:
      X() : m_value(1) 
      ~X() m_value = 0;
   private:
      int m_value;
   ;

void print(Byte *p,int offset)

printf ("Value at %d: 0x%x (%d)\n", offset, p[offset], p[offset]);


void main()

X *x = new X[10];

std::cout << "Address of x: " << x << std::endl;
std::cout << "sizeof(X)   : " << sizeof(X) << std::endl;

Byte *p = (Byte *)x;
print(p,-1);
print(p,-2);
print(p,-3);
print(p,-4);
print(p,-5);
print(p,-6);
print(p,-7);
print(p,-8);
print(p,-9);
print(p,-10);

X *y = new X;
std::cout << "Address of y: " << y << std::endl;

p = (Byte *)y;
print(p,-1);
print(p,-2);
print(p,-3);
print(p,-4);
print(p,-5);
print(p,-6);
print(p,-7);
print(p,-8);
print(p,-9);
print(p,-10);

运行它会得到以下输出(在 Visual Studio 2005 上):

Address of x: 00481DE4
sizeof(X)   : 4
Value at -1: 0x0 (0)
Value at -2: 0x0 (0)
Value at -3: 0x0 (0)
Value at -4: 0xa (10)
Value at -5: 0xc (12)
Value at -6: 0x0 (0)
Value at -7: 0x2f (47)
Value at -8: 0x8 (8)
Value at -9: 0x2f (47)
Value at -10: 0x98 (152)
Address of y: 00481E70
Value at -1: 0xc (12)
Value at -2: 0x0 (0)
Value at -3: 0x2f (47)
Value at -4: 0x8 (8)
Value at -5: 0x2a (42)
Value at -6: 0x98 (152)
Value at -7: 0xf8 (248)
Value at -8: 0xb0 (176)
Value at -9: 0x0 (0)
Value at -10: 0x48 (72)

您可以清楚地看到,在第一种情况下(new[]'d 数组),有 4 个字节用于指示元素的数量(0,0,0,10 合起来就是 10)。

在第二种情况下,这些字节被省略,我们看到与第一种情况相同的模式 (12,0,47,8)。我不确切知道 Visual C++ 将分配的字节数存储在哪里,但它证明元素的数量确实存储在返回的指针之前(在 Visual Studio 2005 中)。

【讨论】:

所以你的意思是,对于new OBJECT[SIZE],我们通常可以在内存中获得一些东西,比如“SIZEOF(OBJECT) SIZE OBJECT”? 实际上是 SIZEOF(OBJECT) NOFELEMENTS。 NOFELEMENTS 由 delete[] 使用,因此它知道要调用多少个析构函数。内存管理器实现使用 SIZEOF(OBJECT) 来了解要释放多少字节。 谢谢。但奇怪的是(parashift.com/c++-faq-lite/compiler-dependencies.html#faq-38.7)他们没有说任何关于“SIZEOF(OBJECT)”的事情:s 更正我之前的评论:它是 NOFBYTESALLOCATED NOFELEMENTS。如果您分配了一个数组,则 NOFBYTESALLOCATED 是 SIZEOF(OBJECT)*NOFELEMENTS 。他们在 FaqLite 中没有提到 sizeof(object) 的原因是 sizeof(object) 或分配的字节数与知道要调用多少个析构函数无关(尽管您可以从 nofbytes 和 sizeof (目的))。分配的字节数仅与管理内存的模块有关,与需要知道要调用的析构函数数量的 C++ 运行时无关。 感谢您的精彩解释!

以上是关于关于delete、delete[]、operator delete()等[重复]的主要内容,如果未能解决你的问题,请参考以下文章

关于js中的delete

关于new delete的说明

关于new和delete中的一些问题

关于new和delete中的一些问题

c++基础_ new, delete概述及其使用!!

关于delete删除select查询出来的结果怎么做