Подтвердить что ты не робот

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

Я понимаю, что в большинстве случаев мы не должны называть деструктор явно. Однако я видел пример из С++ 11 Standard N3485 Раздел 13.4.5. Аргументы шаблона:

Явный вызов деструктора для объекта, который имеет тип, который является специализацией шаблона класса, которая может явно указывать Шаблон-аргументы. Пример:

template<class T> struct A {
    ~A();
}; 

void f(A<int>* p, A<int>* q) {
    p->A<int>::~A();      // OK: destructor call
    q->A<int>::~A<int>(); // OK: destructor call
}

Мне кажется, что мы можем назвать деструктор явно в этом случае, не могли бы вы объяснить мне, почему? Что означает этот вызов деструктора в этом примере? Почему они разумны?

Другой вопрос:

Какие случаи мы можем назвать деструкторами явно, кроме того, когда мы реализуем placement delete?

Спасибо.

РЕДАКТИРОВАТЬ: Я нашел из часто задаваемые вопросы по С++, что мы не должны явно ссылаться на деструктор на локальную переменную.

4b9b3361

Ответ 1

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

Вы имеете в виду, почему мы можем? Потому что язык позволяет явным вызовам деструктора на любом объекте. Как вы говорите, он обычно дает поведение undefined, так как большинство объектов будет уничтожено каким-то другим способом, а поведение undefined - уничтожить что-нибудь дважды (или, более того, для доступа к нему после уничтожения). Но это означает, что вы не должны этого делать, а не то, что язык не позволит вам это сделать.

Или вы имеете в виду, почему мы хотим? Потому что вы уничтожаете объект, созданный с помощью размещения new.

Что означает этот вызов деструктора в этом примере?

Оба они означают одно и то же и эквивалентны p->~A(); они называют деструктор объекта. Пример показывает, что вы можете предоставить аргументы шаблона здесь, если хотите. Я не уверен, почему вы хотите.

В каких случаях мы можем назвать деструкторы явно, кроме размещения delete?

Я думаю, что вам разрешено вызывать тривиальный деструктор (тот, который ничего не делает), когда захотите; но нет смысла. Я думаю, что уничтожение чего-то, созданного с использованием нового места, является единственной законной причиной этого.

Ответ 2

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

Поскольку это разрешено языком, чтобы иметь возможность вызывать деструктор любого объекта всякий раз, когда вы хотите (при условии, что у вас есть доступ, например, он не является частным деструктором).

Что означает этот вызов деструктора в этом примере?

Он просто вызывает деструктор. Логически это означает, что объект разрушен и должен считаться мусором с этой точки и не должен быть разыменован или использован. Технически это означает, что объект находится в любом состоянии, в которое его деструктор оставляет, что для некоторых объектов может быть идентичным построению по умолчанию (но вы никогда не должны полагаться на это).

Почему они разумны?

Иногда вам нужно уничтожать объекты, не освобождая их память. Это происходит во многих классах, таких как вариант/любая, различная система привязки и отражения script, некоторые одноэлементные реализации и т.д.

Например, вы можете использовать std::aligned_storage для выделения буфера для объекта, а затем использовать новое размещение для создания объекта в этом буфере. Вы не можете вызвать delete на этом объекте, так как это вызовет деструктор и попытается освободить память, поддерживающую его. Вы должны явно вызвать деструктор в этом случае, чтобы правильно уничтожить объект.

В каких случаях мы можем назвать деструкторы явно помимо размещения delete?

На самом деле нет такой вещи, как "удаление места размещения", кроме соответствующего оператора для размещения нового (и любые вызовы delete будут неявно вызывать деструктор, кроме тех, которые компилятор вызывает для неудачной сборки, например, ваше "удаление места" ').

Один пример, который я дал выше. Другим примером является std::vector. Вы можете вызвать функции-члены, такие как pop_back(). Этому нужно уничтожить последний элемент в векторе, но он не может использовать delete, поскольку память, поддерживающая объект, является частью большего буфера, который должен управляться отдельно. То же самое касается многих других контейнеров, таких как хеш-таблицы с открытой адресацией, deque и т.д. Это пример того, где вы хотите использовать template typename, чтобы явно вызвать деструктор.

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