Open Source & Linux Lab

It's better when it's simple

User Tools

Site Tools


etc:users:yuri_v_katkov:exception-safety

Безопасный по отношению к исключениям код

Безопасный код в смысле исключений - это код, который при выбрасывании функцией исключения работает следующим образом

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

Нейтральный по отношению к исключениям код - это код, передающий обработку исключения вызывающей функции.

Категории безопасности

  • базовая гарантия - отсутствуют утечки памяти, даже если исключения выбрасываются.
  • строгая гарантия - если операция прекращается из-за генерации исключения, состояние программы остаётся неизменным
  • гарантия отсутствия исключений - исключения не выбрасываются.

Напоминание-ликбез

  • исключение - это такой объект любого типа,
  • операторы try, catch, throw, catch(…)
  • перезапуск исключения
  • спецификация исключений. Нужно ли их писать?
  • terminate(), unexpected()

Требования к функциям

Конструктор

  • должен быть нейтральным
  • может генерировать любые исключения
  • почему после исключения в конструкторе мы не говорим о несогласованном состоянии объекта?

Деструктор и операторы delete

Деструктор не должен генерировать исключения. Этому есть несколько причин:

  • если мы сделаем массив объектов T, где ~T() может генерировать исключения, то что случится, когда при удалении этого массива один из деструкторов выкинет исключение? Ответ такой: память потечет!
class Anarc
{
  ~Anarc()
  {
    throw std::exception;
  }
}
 
int main()
{
  try
  {
    Anarc* mas = new Anarc[3000];
    delete[] mas;
  }
  catch() {}
  ... // какой-то код
}
  • а главное, в Стандарте сказано, что любой код, который веделяет или удаляет массив объектов, деструкторы которых генерируют исключения приводит к undefined behavior

Хорошие практики

  • выполнять сначала код, который может выкинуть исключения и только потом менять состояние объекта

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

  • использовать идиому RAII для управления ресурсами: каждым ресурсом владеет объект. В деструкторе этого объекта происходит освобождение ресурса.
  • использовать функции, не генерирующие исключений (например, swap())

Ссылки

etc/users/yuri_v_katkov/exception-safety.txt · Last modified: 2016/08/08 20:53 by kel