2010-09-02 61 views
3

可能重复:
How does delete[] “know” the size of the operand array?
(POD)freeing memory : is delete[] equal to delete ?关于删除,删除[],delete操作符()等

据我了解,下面

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

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

正如我在TC++ PL,这种“的存储器适量”读取这样确定:

要解除分配被新分配的空间,删除和删除[]必须能够确定大小分配的对象。这意味着使用新的标准实现分配的对象将比静态对象占用稍多的空间。通常,一个单词用于保存对象的大小。

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

你能说清楚吗?

我想这个答案可能会帮助我了解delete []如何工作。我了解new []将工作,并delete []将首先呼吁和解除分配这一切记忆“所有的数组对象”析构函数...

delete []怎么能知道数组的大小?

感谢您的帮助!

+0

我认为这是依赖于实现的,但更多的启发性的人肯定会更具体。 – ereOn 2010-09-02 09:26:57

+0

无主复制,对不起。 – 2010-09-02 09:38:13

+0

相关:[(POD)释放内存:是删除\ [\]等于删除?](http://stackoverflow.com/questions/1553382/pod-freeing-memory-is-delete-equal-to-delete) – sbi 2010-09-02 09:55:04

回答

3

这一切都取决于实施。

大多数运行时间确实会在返回的内存之前存储内存大小((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) 

你可以清楚地看到,在第一种情况下(新的[]'d数组),有4个字节用于表示元素的数量(0,0,0,10,这使得数值10)。

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

+0

所以你的意思是说,对于'新的OBJECT [SIZE]'我们通常可以在内存中获得类似“SIZEOF(OBJECT)SIZE OBJECT”的东西? – 2010-09-02 09:35:19

+1

其实SIZEOF(OBJECT)NOFELEMENTS。 NOFELEMENTS被delete []使用,所以它知道要调用多少个析构函数。内存管理器实现使用SIZEOF(OBJECT)来知道要释放多少个字节。 – Patrick 2010-09-02 09:45:59

+0

Thx。但奇怪的是,在那里(http://www.parashift.com/c++-faq-lite/compiler-dependencies.html#faq-38.7)他们没有说“SIZEOF(OBJECT)”:s – 2010-09-02 09:48:15