Стандарты программирования на С++. 101 правило и рекомендация - [70]

Шрифт
Интервал

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

В действительности же спецификации исключений делают нечто вроде бы и незначительное, но фундаментально отличающееся: они заставляют компилятор ввести в программу дополнительный код в форме неявных блоков >try/>catch вокруг тела функции для обеспечения проверки времени выполнения того, что функция действительно генерирует только перечисленные исключения или не генерирует их вообще, кроме тех случаев, когда компилятор может статически доказать, что спецификация исключений никогда не будет нарушена. В последнем случае компилятор может оптимизировать код, убрав описанную проверку. Спецификации исключений, кроме того, могут помешать дальнейшей оптимизации кода компилятором — так, например, некоторые компиляторы не могут делать встраиваемыми функции, имеющие спецификации исключений.

Однако хуже всего то, что спецификации исключений — очень "тупой" инструмент: при нарушении они по умолчанию немедленно прекращают выполнение программы. Вы можете зарегистрировать функцию-обработчик данного нарушения, но этот вряд ли вам поможет, поскольку такой обработчик только один на всю программу, и все, что он может сделать для того, чтобы избежать немедленного завершения программы, — это сгенерировать допустимое исключение. Но, напомним, такой обработчик — единственный для всего приложения, так что трудно представить, как можно сделать что-то полезное в такой ситуации или как узнать, какое исключение можно повторно сгенерировать в нем без вмешательства во все спецификации исключений (например, определить, что все спецификации исключений должны

включать некоторое общее исключение >UnknownException, генерируемое обработчиком. Заметим, что это автоматически уничтожит все преимущества от использования спецификаций исключений).

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

Снижение производительности в обмен на введение ограничений практически всегда бесполезно. Это отличный пример преждевременной пессимизации (см. рекомендацию 9).

Нет простого пути решения описанных в данной рекомендации проблем. В частности, проблемы не решаются путем перехода к статическим проверкам. Программисты часто предлагают перейти от динамической проверки спецификаций исключений к статической, как это делается в Java и других языках программирования. Коротко говоря, это просто означает поменять шило на мыло, т.е. один ряд проблем на другой. Пользователи языков со статической проверкой спецификаций исключений не менее часто предлагают перейти к динамической проверке…

Исключения

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

>class Base { //...     // В чужом классе имеется

> virtual f()           // спецификация исключений,

>  throw(X, Y, Z) ;     // и если вы не можете

>};                     // ее удалить...


>class MyDerived

> : public Base { //... // ... то в вашем классе при

> virtual f()           // перегрузке функции она должна

>  throw(X, Y, Z);      // иметь совместимую (желательно

>};                     // идентичную) спецификацию исключений

Из опыта [BoostLRG] следует, что только пустые спецификации исключений (т.е. >throw()) у невстраиваемых функций "могут давать некоторое преимущество у некоторых компиляторов". Не слишком оптимистичное заявление для одного из наиболее продвинутых, разрабатываемого экспертами мирового уровня проекта…

Ссылки

[BoostLRG] • [Stroustrup00] §14.1, §14.6 • [Sutter04] §13

STL: контейнеры

Если вам нужен контейнер, по умолчанию используйте >vector.

— Бьярн Страуструп (Bjarne Stroustrup),
[Stroustrup00] §17.7

Мы знаем, что вы уже предпочитаете использовать стандартные контейнеры вместо написанных вручную. Но какой именно контейнер следует использовать? Что должно (и что не должно) храниться в контейнерах и почему? Как следует заполнять контейнеры? Какие важные идиомы надо знать?

В этом разделе имеются ответы на все перечисленные (и не только) вопросы. И не случайно, что три первые рекомендации в нем содержат слова "Используйте >vector...".

В этом разделе мы считаем наиболее значимой рекомендацию 79 — "Храните в контейнерах только значения или интеллектуальные указатели". К ней мы добавим — если даже вы не планируете применять [Boost] и [C++TR104] для иных целей, все равно воспользуйтесь их интеллектуальным указателем


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.