Как delete[] знает сколько элементов нужно удалить
Что проверяют
Понимаете ли вы, что за new[] и delete[] стоит не магия, а договорённость компилятора и аллокатора. Хороший ответ разделяет две задачи: сколько вызвать деструкторов и сколько байт вернуть. Следом часто спрашивают, что будет, если освободить массив обычным delete.
Как отвечать
Стандарт C++ механизм не описывает, он только требует освобождать память из new[] через delete[]. На практике всё устроено так:
- число элементов (array cookie): если у типа нетривиальный деструктор,
new T[n]просит уoperator new[]чуть больше памяти и записываетnперед первым элементом. Наружу возвращается указатель уже после этого поля.delete[]отступает назад, читаетnи вызывает деструкторы в обратном порядке. Так делают Itanium C++ ABI (GCC, Clang) и MSVC; - размер блока: его знает сам аллокатор.
mallocхранит служебный заголовок рядом с блоком, поэтомуfreeразмер не нужен; - тривиальные типы: для
new int[10]в распространённых ABI cookie обычно не пишется, деструкторы вызывать не надо, а размер блока аллокатор и так знает.
Поэтому для int смешение new[] и delete часто «работает», а для класса с деструктором ломает кучу: delete отдаст аллокатору указатель, смещённый относительно начала блока, и вызовет деструктор только у первого элемента. По стандарту оба случая это неопределённое поведение.
Закончите практическим выводом: в современном коде ручной new[] почти не нужен. Есть std::vector, а для владеющего указателя на массив std::unique_ptr<T[]> и std::make_unique<T[]>(n), которые сами вызывают правильную форму удаления.
Где спотыкаются
Утверждают, что размер всегда лежит перед массивом, и предлагают прочитать его через reinterpret_cast. Это деталь реализации, для тривиальных типов её нет, полагаться на неё нельзя.
Считают, что delete вместо delete[] для int допустим, раз деструкторов нет. Это всё равно UB, и AddressSanitizer сообщит о нём как alloc-dealloc-mismatch.
Удаляют массив наследников через указатель на базу: Base* p = new Derived[n]; delete[] p;. Шаг по элементам считается по размеру Base, поведение не определено даже при виртуальном деструкторе.