В C/C++ для того чтобы обработать массив нужно знать его размер. Соответственно нужно всегда этот размер "помнить" и протаскивать во все функции обработки в качестве аргумента. Например:
void foo(int* arr, size_t n) {
for (size_t i = 0; i < n; i++) {
arr[i] = i * i;
}
}
Но при освобождении ресурсов знать размер почему-то необязательно. Можно просто вызвать free(arr) если память выделялась через malloc() или calloc(). Или можно использовать оператор delete[] arr; если память выделялась через оператор new int[n]
Вопрос откуда C/C++ знает сколько надо освободить памяти, если не знает размер массива? Функция free() и оператор delete[] не принимают в качестве аргументов размер массива, а только указатель на массив. А если C/C++ может каким-то образом вычислить размер, то зачем его постоянно "таскать" с собой в отдельной переменной?
Ответ
Все это - детали реализации.
В популярных реализациях malloc обычно записывает размер выделенного блока в начало выделенного блока. Возвращенный вам указатель обычно указывает на память сразу за этим записанным размером. free знает, где искать размер блока, и извлекает его именно оттуда.
По умолчанию new и delete просто делегируют запросы на выделение и освобождение сырой памяти в тот же самый malloc и free или их аналоги, через посредство operator new и operator delete.
При работе с массивами объектов с тривиальными деструкторами new[] и delete[] фактически ведут себя точно так же: вызывают в конечном итоге malloc с правильно вычисленным общим размером массива и вызывают free для освобождения памяти.
При работе с массивами объектов с нетривиальными деструкторами все несколько сложнее: new[] дополнительно записывает в начало блока памяти точное количество элементов создаваемого массива, а delete[] потом извлекает это количество и вызывает правильное количество деструкторов.
Допустим, если у вас есть какой-то класс MyNonTrivialClass размером в 9 байт с нетривиальным деструктором, то выполнение
MyNonTrivialClass *p = new MyNonTrivialClass[17];
приведет к формированию блока памяти со следующей внутренней структурой
+-----+-----+------+------+------
| 176 | 17 | p[0] | p[1] | ...
+-----+-----+------+------+------
^ ^ ^
| | |
| | p - полученный вами указатель
| |
| поле типа `size_t` (8 байт), записано `new[]`
|
поле типа `size_t` (8 байт), записано `malloc`
`new[]` запросил 161 байт = 17 * 9 + 8, размер выровнен до границы 16 байт
Конкретные значения могут отличаться, но общая идея обычно в популярных реализациях именно такая.
См. также https://ru.stackoverflow.com/a/770300/182825
Комментариев нет:
Отправить комментарий