How does C / C++ know how much memory to free up if it doesn't know the size of the array?

In C / C++, in order to process an array, you need to know its size. Accordingly, you 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, it is not necessary to know the size for some reason. You can simply call free(arr) if the memory was allocated via malloc() or calloc(). Or you can use the delete[] arr; operator if the memory was allocated via the new int[n] operator.

Question how does C / C++ know how much do I need to free up memory if I don't know the size of the array? The free() function and the delete[] operator do not take the array size as arguments, but only a pointer to the array. And if C / C++ can somehow calculate the size, then why constantly "drag" it with you in a separate variable?

Author: abg, 2018-03-10

2 answers

These are all implementation details.

  • malloc / free

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

  • new / delete

    By default, the regular new and delete (without []) simply delegate requests to allocate and deallocate raw data. memory in the same malloc and free or their analogues, via operator new and operator delete.

  • new[] / delete[]

    When working with arrays of objects with trivial destructors new[] and delete[] actually behave exactly the same: call eventually malloc with a correctly calculated total array size, and call free to free up 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 created array to the beginning of the allocated block, and delete[] then extracts this number and calls the correct number of destructors.

    For example, if you have a 9-byte class MyNonTrivialClass with a non-trivial destructor, then executing

    MyNonTrivialClass *p = new MyNonTrivialClass[17];
    

    Will result in the formation of 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 the values may differ, but the general idea is usually the same in popular implementations.

    --

    In addition to non-trivial destructors, there is another situation in the language that usually forces new[] to store the number of array elements at the beginning of the allocated block: when an array of objects containing an overloaded operator delete[](void *, std::size_t) is created, i.e., a memory release function with a second parameter of the std::size_t type. When freeing up memory, implementations are required to pass through this the parameter is the same value that was passed to the corresponding call operator new[]. To do this, they need to store the exact size of the array.

    Tellingly, Microsoft Visual Studio to this day (VS2019) ignores this language requirement, does not store the array size, and passes an incorrect size value to such operator delete[].

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

 37
Author: AnT, 2019-11-10 03:18:35

Generally speaking, the memory manager knows this. For example, somewhere before the start of the allocated block, there is some service area that indicates what and how much is allocated.

Only this is the matter of the memory manager, which is related to the language "insofar as" - these are the problems of a specific implementation, what to do and how to do it. So the language is not able to calculate the dimension.

 13
Author: Harry, 2018-03-10 18:17:03