4

Possible Duplicates:
How does delete[] “know” the size of the operand array?
( POD )freeing memory : is delete[] equal to delete ?

As I understand, the following

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

will result first in a call to operator new() (the global one, or a specialized one provided by A) to allocate the right amount of memory and then to a call to the constructor of A. And when delete is called, is will first call the destructor of A, and then call operator delete() to deallocate the "right amount of memory".

As I read in TC++PL, this "right amount of memory" is determined like that:

To deallocate space allocated by new, delete and delete[] must be able to determine the size of the object allocated. This implies that an object allocated using the standard implementation of new will occupy slightly more space than a static object. Typically, one word is used to hold the object's size.

This makes sense. But where is this word stored to be accessible by delete ? Just before the address pointed by the new pointer ? So that delete can obtain the size to be deleted by accessing a-sizeof<void*> ?

Can you clarify this ?

I think the answer to that may help me to understand how delete [] works. I understand how new [] will work, and that delete [] will first call the destructors for "all the objects of the array" and the deallocate all this memory...

But how can delete [] know the size of the array ?

Thanks for your helpful answers !

Community
  • 1
  • 1
Cedric H.
  • 7,980
  • 10
  • 55
  • 82
  • I think this is implementation dependant, but more enlighted people will surely be more specific. – ereOn Sep 02 '10 at 09:26
  • related: [( POD )freeing memory : is delete\[\] equal to delete ?](http://stackoverflow.com/questions/1553382/pod-freeing-memory-is-delete-equal-to-delete) – sbi Sep 02 '10 at 09:55

1 Answers1

3

It all depends on the implementation.

Most run-times will indeed store the memory size just before the returned memory ((BYTE *)p-sizeof(size_t)) but there are other alternatives. In my own memory manager (yes, I write this kind of stuff), I have a more complex data structure (using pointers to linked lists, checksums, ...) before the returned memory. It is actually up to the memory manager to decide where to store this information.

Besides the size of the allocated memory, new[] will also store the number of instances so it knows how many destructors to call. This is normally beyond the scope of the memory manager, and is normally handled by the C++ runtime/compiler itself. But again, where this number of instances is stored depends on the compiler, although in practice I would expect this to be stored just before the returned memory (and just after any data stored by the memory manager.

EDIT: The following small utility shows the memory layout before the allocated memory:

#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);
}

Running this gives the following output (on 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)

You can clearly see that in the first case (the new[]'d array), that there are 4 bytes used to indicate the number of elements (0,0,0,10 which makes together the value 10).

In the second case, these bytes are omitted and we see the same pattern (12,0,47,8) as in the first case. I don't know exactly where Visual C++ stores the number of allocated bytes, but it proves that the number of elements is indeed stored before the returned pointer (in Visual Studio 2005).

Patrick
  • 23,217
  • 12
  • 67
  • 130
  • So you mean that for `new OBJECT[SIZE]` we could typically obtain something in memory like " SIZEOF(OBJECT) SIZE OBJECT" ? – Cedric H. Sep 02 '10 at 09:35
  • 1
    Actually SIZEOF(OBJECT) NOFELEMENTS. The NOFELEMENTS is used by delete[] so it knows how many destructors to call. SIZEOF(OBJECT) is used by the memory manager implementation to know how many bytes to free. – Patrick Sep 02 '10 at 09:45
  • Thx. But what is strange is that there (http://www.parashift.com/c++-faq-lite/compiler-dependencies.html#faq-38.7) they don't say anything about "SIZEOF(OBJECT)" :s – Cedric H. Sep 02 '10 at 09:48
  • 1
    Correction to my previous comment: it is NOFBYTESALLOCATED NOFELEMENTS. And NOFBYTESALLOCATED is SIZEOF(OBJECT)*NOFELEMENTS if you allocated an array. The reason why they don't mention sizeof(object) in FaqLite is that the sizeof(object), or the number of allocated bytes is irrelevant to know how many destructors to call (although you could derive the number of elements from nofbytes and sizeof(object)). The number of allocated bytes is only relevant for the module that manages the memory, not for the C++ run time who needs to know the number of destructors to call. – Patrick Sep 02 '10 at 10:04