Ответ
Технически — да, но это крайне опасная практика, которой следует избегать. Деструктор — это часть процесса уничтожения объекта, и его основная задача — освобождение ресурсов, а не создание новых сущностей.
Критические риски:
-
Исключения: Начиная с C++11, деструкторы по умолчанию неявно объявлены как
noexcept(true). Если в таком деструкторе будет выброшено исключение (например, при неудачном выделении памяти для нового объекта), программа немедленно завершится черезstd::terminate(). -
Утечки памяти: Создание динамического объекта (
new) в деструкторе и потеря указателя на него — прямая дорога к утечке. -
Нарушение инвариантов и неопределенное поведение: Создание объекта может иметь побочные эффекты (изменение глобального состояния, блокировка мьютекса), которые нарушают ожидания от фазы разрушения.
Пример проблемного кода:
class Logger {
static std::vector<std::string>* globalLog;
public:
~Logger() noexcept(false) { // Опасно снимать noexcept!
// Попытка создать объект в деструкторе.
if (!globalLog) {
globalLog = new std::vector<std::string>(); // (1) Потенциальная утечка
}
globalLog->push_back("Logger destroyed"); // (2) Может выбросить std::bad_alloc
}
};
// Если push_back выбросит исключение, а деструктор noexcept(true) -> terminate.
Когда это может быть оправдано? Почти никогда. Единственный условно приемлемый случай — создание объекта с статической продолжительностью хранения (static), время жизни которого привязано ко всей программе, но и это часто признак плохого дизайна.
Правильная альтернатива: Логика, которая должна выполняться «после» разрушения объекта, должна быть вынесена в отдельный метод (например, shutdown(), finalize()), который вызывается явно до деструктора. Деструктор должен быть простым и надежным.