9 декабря 2010 г.

STL: есть ли жизнь без исключений

Известно, что при компиляции кода можно отключить обработку исключений компилятором (например, опцией -fno-exceptions в GCC, или /EHs- в Visual Studio). Однако, отключение обработки исключений вовсе не означает, что программа не будет генерировать исключения. Это всего лишь означает, что компилятор не будет создавать код для обработки исключений и уничтожения автоматических объектов. А исключения будут продолжать генерироваться — операторами new при нехватке памяти, методом at() класса std::vector при выходе за пределы массива, просто операторами throw расставленными программистом по своему коду и т. д. Различие лишь в том, что так как в программе не будет вообще никакого кода, перехватывающего исключения, то любое сгенерированное в программе исключение приведет к вызову terminate().

Классы стандартной библиотеки сообщают об ошибках только с помощью исключений и никак иначе. Проблема использования STL в том, что когда мы отключаем поддержку исключений в проекте, то лишаемся механизма обработки ошибок. И если проблему с оператором new можно решить его заменой на new (nothrow), то исключение, генерируемое в аллокаторе при вызове vector::resize(), вроде как ничем не заменишь.

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

Я обнаружил, что в зависимости от условий разработки и требований к продукту возможны всего три варианта:
  1. Оценить вероятность и последствия возможных ошибок, понять, что не всё так страшно, и вообще забить на исключения. В этом случае возникновение ошибок просто напросто приведет к завершению программы.
  2. Использовать нестандартные (третьесторонние) имплементации для обработки ошибок или средства самой платформы. Как правило, получаются корректные, но не портируемые решения.
  3. Использовать сложный, но портируемый способ — отказаться от операторов, алгоритмов и классов, генерирующих исключения. Например, использовать new (nothrow) вместо new, имплементировать аллокаторы со статически зарезервированными блоками памяти, при работе с контейнерами проверять состояние аллокаторов до вызова методов, которые могут вызвать allocate(), не использовать методы, вроде vector::at() и т. д.
В общем получается, что жизнь STL без исключений возможна, но не проста.

1 комментарий:

  1. Есть ещё один вариант - вынести работу с STL в отдельную динамически подгружаемую библиотеку, спрятав все детали реализации под интерфейс.
    Если возникнет нужда/найдутся альтернативы - переписываем с STL на иные конструкции (либо как вы описали в посте) и втягиваем в проект статической либой

    ОтветитьУдалить