Ответ 1
Если создание какого-либо объекта в буфере вызывает исключение, ранее созданные объекты должны быть уничтожены. Это требует доступного деструктора.
Из стандарта С++ 17 (черновик здесь) [expr.new]:
Если новое выражение создает объект или массив объектов типа класса, доступ и управление неоднозначностью выполняются для функции выделения, функции освобождения и конструктора. Если new-выражение создает массив объектов типа класса, деструктор потенциально вызывается.
Почему new[]
вызывает деструктор? Это новое, в конце концов. Это не удалить.
Если создание какого-либо объекта в буфере вызывает исключение, ранее созданные объекты должны быть уничтожены. Это требует доступного деструктора.
Вы не учли слово "потенциально" в цитате, которую вы упомянули в стандарте.
Это означает, что существует вероятность того, что вызов деструктора может произойти. И это произойдет, если при построении какого-либо объекта в массиве возникнет исключение.
В сочетании со следующей цитатой из [class.dtor]/12.4
которой упоминается [expr.new]
, это становится понятным.
В каждом случае контекст вызова - это контекст построения объекта. Деструктор также вызывается неявно через использование выражения удаления для созданного объекта, выделенного новым выражением; контекст вызова - выражение удаления. [Примечание: Массив типа класса содержит несколько подобъектов, для каждого из которых вызывается деструктор. - примечание конца] Деструктор также может быть вызван явно. Деструктор потенциально вызывается, если он вызывается или как указано в
[expr.new]
,[class.base.init]
и[except.throw]
. Программа плохо сформирована, если потенциально вызываемый деструктор удален или недоступен из контекста вызова.
В бою:
#include <iostream>
int counter;
class Destruct
{
public:
Destruct()
{
if (counter++ > 5)
throw counter;
}
~Destruct()
{
std::cout << "Dtor called\n";
}
};
int main()
{
try
{
new Destruct[10];
}
catch (...){}
}
Вы увидите что-то вроде:
Dtor called
Dtor called
Dtor called
Dtor called
Dtor called
Dtor called