Почему деструктор вызывается для объекта, который не удаляется?


struct A
{
    ~A() = delete;
};

int main()
{
    new A{};
}

это не удается скомпилировать с сообщением об ошибке:

ошибка: использование удаленной функции ' A::~A()' новый A{};

Как я понимаю, я не уничтожаю объект, так почему он пытается вызвать деструктор?

составлен с GCC 8.1.0

g++ -std=c++17 -O2
3 56

3 ответа:

Это ошибка gcc 57082.


давайте пойдем снизу вверх.

[dcl.ПКТ.защита.удалить]/2:

программа, которая ссылается на удаленную функцию неявно или явно, кроме как для ее объявления, плохо сформирована.

ясно, что мы не имеем в виду ~A() явно. Мы имеем в виду это неявно? [класс.dtor]/12:

деструктор вызывается неявно

  • для построенного объекта со статической длительностью хранения ([basic.НТЦ.static]) при завершении программы ([basic.начать.термин]),
  • для построенного объекта с длительностью хранения потока ([basic.НТЦ.thread]) при выходе из потока,
  • для построенного объекта с автоматическим сроком хранения ([basic.НТЦ.auto]) при выходе из блока, в котором создается объект ([stmt.dcl]),
  • для построенного временного объект, когда его срок службы заканчивается ([conv.rval], [класс.временный.)]

или [expr.new] / 20:

если new-expression создает массив объектов типа класса, деструктор вызывается, потенциально.

у нас есть что-нибудь из этого? Нет, здесь нет объекта с автоматической, статической или потоковой длительностью хранения, а также нет построенного временного объекта и нашего new-expression создание массива. Здесь есть только один объект, один A с динамической продолжительностью хранения, которую мы агрегируем-инициализируем.

поскольку мы ни явно, ни неявно ссылаемся на ~A(), мы не можем споткнуться об это правило. Следовательно, ошибка gcc. Обратите внимание также, что gcc принимает new A; и new A();, которые имеют то же значение, что и это правило.

вероятно, ошибка gcc здесь.

стандарт указывает, что деструктор потенциально вызывается, когда новое выражение создает массив [expr.новое]:

Если новое выражение создает объект или массив объектов типа класса, управление доступом и неоднозначностью выполняется для функции выделения, функции освобождения и конструктора. если новое выражение создает массив объектов типа класса, деструктор потенциально вызывается.

выделено мной

gcc применяет также это правило при создании не массива, который неявно не является стандартным правилом. благодаря приведенным ниже комментариям кажется, что gcc делает прямо противоположное: при создании не массива он считает деструктор потенциально вызываемым, а при создании массива он просто не проверяет деструктор.

насколько я могу судить, никакие объекты не уничтожаются в Примере, и это происходит при компиляции, если выражение изменяется на new A;

Я думаю, что пример кода не компилируется-это ошибка в GCC. Clang компилирует его просто отлично.


ответ для недавно добавленного тега языка-юриста.

решающее стандартное правило-это в [class.dtor]:

деструктор вызывается неявно

... случаи, которые не применяются с другими длительностями хранения, чем динамические ...

... Деструктор также вызывается неявно с помощью delete-выражения (5.3.5) для построенного объекта, выделенного новое выражение (5.3.4); контекст вызова-это выражение удаления. [ Примечание: массив класса тип содержит несколько подобъектов, для каждого из которых вызывается деструктор. - конец Примечание ] деструктор может также вызывается явно. Деструктор-это потенциально вызывается, если он вызывается или как указано в 5.3.4, 12.6.2, и 15.1.

5.3.4 is [expr.new] который только указывает

... Если new-expression создает массив объектов типа class, деструктор потенциально вызывается (12.4).

что не относится.

12.6.2 является [класс.основа.init] который только указывает

в конструкторе без делегирования деструктор для каждого потенциально построенный подобъект типа класса является потенциально вызывается (12.4).

который не применяется

15.1 is [except.throw], который указывает, как объект исключения уничтожается, который не применяется

вывод: Ни один из разделов 5.3.4, 12.6.2, и 15.1. содержит правило, которое применяется к этому случаю, и деструктор не вызывается, а также не существует выражения delete. Поэтому деструктор потенциально не вызывается, поэтому он хорошо сформирован чтобы деструктор был удален.