In C / C ++, in order to process an array, you need to know its size. Accordingly, one should always “remember” this size and drag it into all processing functions as an argument. For example:

void foo(int* arr, size_t n) { for (size_t i = 0; i < n; i++) { arr[i] = i * i; } } 

But when releasing resources, knowing the size for some reason is not necessary. You can simply call free(arr) if memory is allocated through malloc() or calloc() . Or you can use the delete[] arr; operator delete[] arr; if memory is allocated through the operator new int[n] .

The question is where does C / C ++ know how much memory should be freed if it does not know the size of the array? The free() function and the operator delete[] do not take as an argument the size of the array, but only a pointer to the array. And if C / C ++ can somehow calculate the size, then why is it constantly “dragging” with it in a separate variable?

  • one
    The concept of "dimension" is not synonymous with the concept of "size." "Dimension" - the number of measurements , "size" - the number of elements . - VladD
  • GNU has a malloc_usable_size function, but it can return a larger value than you requested in malloc, creating an array. So drag everywhere its size ... - avp

2 answers 2

All this - implementation details.

In popular implementations, malloc usually writes the size of the selected block to the beginning of the selected block. The pointer returned to you usually points to the memory immediately after this recorded size. free knows where to look for the block size, and retrieves it from there.

By default, the usual new and delete (without [] ) simply delegate requests to allocate and free raw memory to the same malloc and free or their equivalents, through operator new and operator delete .

When working with arrays of objects with trivial destructors, new[] and delete[] actually behave in exactly the same way: eventually they call malloc with a correctly calculated total size of the array and call free to free memory.

When working with arrays of objects with non-trivial destructors, everything is somewhat more complicated: new[] requests a little more memory from malloc and additionally writes the exact number of elements of the array to be created at the beginning of the selected block, and delete[] then extracts this number and calls the correct number of destructors.

Suppose if you have a MyNonTrivialClass of 9 bytes with a non-trivial destructor, then

 MyNonTrivialClass *p = new MyNonTrivialClass[17]; 

will result in a memory block with the following internal structure

 +-----+-----+------+------+------ | 176 | 17 | p[0] | p[1] | ... +-----+-----+------+------+------ ^ ^ ^ | | | | | p - полученный вами указатель | | | поле типа `size_t` (8 байт), записано `new[]` | поле типа `size_t` (8 байт), записано `malloc` `new[]` запросил 161 байт = 17 * 9 + 8, размер выровнен до границы 16 байт 

Specific values ​​may differ, but the general idea is usually in popular implementations that way.

See also https://ru.stackoverflow.com/a/770300/182825

  • Tell me, is there any point in recording the number of elements if the size of one element is known? Or are there any subtleties? - selya
  • one
    @selya: I do not quite understand the question. First, malloc can easily round up the size of the allocated block in a big way and save exactly the rounded size. In such a situation, the division of the saved size of the whole block by the element size does not necessarily exactly coincide with the actual size of the array. Secondly, the raw memory allocation mechanism can easily be overloaded and delete[] will lose access to the block size altogether. Therefore, if necessary, the size of the array new[] always stored separately and independently. - AnT
  • it just seems to me that it is, at least, not logical - even the number of elements of the tail. It seems to me that a concrete implementation should quite well know how it is rounded up, and the issue of recording also the number of elements is not worth it ... - selya
  • @selya: What does "know" here? If the size is rounded, then the number cannot be restored, regardless of whether the implementation “knows” about the rounding or does not know. And, once again, do not forget that the mechanism for allocating raw memory is overloaded. - AnT
  • A simple experiment will show you these dimensions: coliru.stacked-crooked.com/a/f8fa350da0f46bd2 - AnT

Generally speaking, the memory manager knows this. For example, somewhere before the beginning of a selected block there is some kind of service area in which it is indicated what and how much is allocated.

Only this is the business of the memory manager, who is related to the language "as far as" - these are problems of a concrete implementation, what and how to do. So the language is not able to calculate the dimension.