В недавнем интервью меня попросили ответить, безопасен ли этот код и будет ли когда-нибудь использовать что-то вроде этого:
template<class T> T *CTricky<T>::Safe_Or_Not (T *object)
{
object->T::~T ();
::new (object) T;
return object;
}
Мой ответ был: этот код безопасен, и я бы использовал эту технику, если бы мне нужно было освободить ресурсы, используемые моим «объектом», вызвав его деструктор, но в то же время я не хотел освобождать свой «объект» и хотел это держать его место в памяти (достигается путем размещения нового здесь).
Честно говоря, я не ищу помощи, чтобы правильно ответить на этот вопрос на собеседовании. Мне только любопытно узнать, правильное ли мое понимание размещения новых и явных вызовов деструкторов.
это НЕ безопасный:
Следующее может привести к утечке памяти 🙁https://ideone.com/70YqhM)
Base* b = new Derived;
b = Safe_Or_Not(b);
Производный деструктор никогда не называется.
И как другое упоминание:
Короткий ответ: хотя это не обязательно вызывает проблемы, сделать это действительно безопасно довольно сложно. Самая большая проблема заключается в том, что если конструктор вызывается с помощью размещения новых бросков, вы уже уничтожили объект, но при раскручивании стека он снова попытается уничтожить его, что приведет к неопределенному поведению.
Хотя есть несколько других вещей, на которые нужно обратить внимание (например, нулевой указатель), это, пожалуй, наименее очевидный и наиболее трудный, чтобы он не вызывал проблем (в основном, ваш единственный выбор — мириться с неопределенным поведением и надейтесь на лучшее или поймайте исключение и выйдите из программы до того, как раскрутка стека может произойти).
Я думаю, что общая логика «явный вызов деструктора + размещение нового» безопасна.
Однако этот код не является безопасным, потому что:
— Вы не проверяете, является ли указатель нулевым.
— исключительная безопасность не учитывается