Рассмотрим класс finally
работает произвольный пользовательский код в деструкторе.
Вот самая минимальная реализация (без пересылки, вспомогательной функции и т. Д.):
template<typename Func>
class finally
{
public:
finally(Func f) : f_(f) {}
~finally() { f_(); }
private:
Func f_;
};
Вопрос в том, как следует обрабатывать исключения в пользовательском коде. ,
Вот варианты, которые я мог бы придумать, какой из них, по вашему мнению, лучше, если предположить, что класс предполагается использовать в широком диапазоне ситуаций?
1) Ничего не делать. ~finally() /*noexcept*/ { f_(); }
Разрушитель finally
неявно noexcept
поэтому любое исключение в коде пользователя приводит к terminate()
,
Пользователь должен каждый раз думать об отсутствии исключений в своем коде и защищать его вручную с помощью try / catch, если он выбрасывает.
2) Полностью прозрачный деструктор. ~finally() noexcept(f_()) { f_(); }
Разрушитель finally
условно noexcept
поэтому любое исключение передается и terminate()
вызывается, только если это происходит во время разматывания стека.
Пользователь, вероятно, должен подумать о сценариях раскрутки стека, но terminate()
в таких ситуациях может быть правильным решением по умолчанию.
3) Поймай все исключения в деструкторе. ~finally() { try { f_(); } catch (...) {} }
Классический деструктор ничего не бросает.
Ограничивает возможности пользователя по проверке ошибок с исключениями, но с хорошим намерением. Вероятно, менее эффективный из-за блока try / catch. Пользователь не должен думать ни о чем.
3+) (Вероятно) оптимизирован 3), использует специализацию / SFINAE, чтобы опустить блок try / catch, если f_()
является noexcept
,
Может избыточно включать функции C, такие как fclose(FILE*)
в блоке try / catch, поскольку они не исключаются, но такие функции, вероятно, не используются с параметром finally напрямую, а через лямбды, которые также легко можно не пометить как noexcept
из забывчивости.
4) Статическое утверждение, что f_()
нет, кроме
Пользователь должен явно пометить свой код как noexcept
каждый раз, то ловить или не ловить исключения — его забота. Опять же ограничивает возможности пользователя по проверке ошибок с исключениями, но с хорошим намерением.
4+) 4) плюс некоторая специализация finally (может быть, даже другого отдельного шаблона класса) с семантикой 2), которая свободна от утверждения, но должна использоваться явно.
Задача ещё не решена.
Других решений пока нет …