Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - [42]

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

Для некоторых функций отсутствие исключений настолько важно, что они являются >noexcept по умолчанию. В С++98 считается плохим стилем разрешать генерировать исключения функциям освобождения памяти (т.e. операторам >operator delete и >operator delete[]) и деструкторам, а в C++11 это правило стиля стало правилом языка. По умолчанию все функции освобождения памяти и все деструкторы — как пользовательские, так и генерируемые компиляторами — неявно являются >noexcept. Поэтому необходимости явно объявлять их таковыми нет. (Это ничему не повредит, это просто необычно.) Единственная ситуация, когда деструктор не является неявно объявленным как >noexcept, — это когда член-данные класса (включая унаследованные члены и содержащиеся внутри других членов-данных) имеет тип, который явно указывает, что его деструктор может генерировать исключения (например, объявленный как >noexcept(false)). Такие деструкторы являются редкостью. Их нет в стандартной библиотеке, и если деструктор объекта, используемого стандартной библиотекой (например, как элемент контейнера или переданный алгоритму аргумент), генерирует исключение, поведение программы является неопределенным.

Стоит отметить, что некоторые проектировщики библиотечных интерфейсов различают функции с широкими контрактами от функций с узкими контрактами. Функция с широким контрактом не имеет предусловий. Такая функция может быть вызвана независимо от состояния программы и не накладывает никаких ограничений на аргументы, передаваемые ей вызывающим кодом[9]. Функции с широким контрактом никогда не демонстрируют неопределенного поведения.

Функции без широких контрактов имеют узкие контракты. Если предусловия для таких функций нарушены, их результаты являются неопределенными.

Если вы пишете функцию с широким контрактом и знаете, что ее не покинут никакие исключения, легко следовать совету из данного раздела и объявить ее как >noexcept. Для функций с узкими контрактами ситуация сложнее. Предположим, например, что вы пишете функцию >f, принимающую параметр >std::string, и пусть естественная реализация >f никогда не генерирует исключений. Это предполагает, что функция >f должна быть объявлена как >noexcept.

Предположим теперь, что >f имеет предусловие: длина ее строкового параметра >std::string не должна превышать 32 символа. Если >f вызывается со строкой >std::string, длина которой больше 32 символов, поведение будет неопределенным, поскольку нарушение предусловия по определению приводит к неопределенному поведению. Функция >f не обязана проверять это предусловие, так как функции могут считать свои предусловия выполненными. (За обеспечение выполнения таких предположений отвечает вызывающий код.) Тогда даже при наличии предусловия объявление >f как >noexcept выглядит целесообразным:

>void f(const std::string& s) noexcept; // Предусловие:

>                                       // s.length() <= 32

Но предположим, что разработчик >f решил проверять нарушения предусловия. Такая проверка не обязательна, но она и не запрещена; более того, проверка предусловия может быть полезной, например, в процессе системного тестирования. Отладка сгенерированного исключения в общем случае проще, чем попытки отследить причину неопределенного поведения. Но как следует сообщать о нарушении предусловий, чтобы проверки (или клиентский обработчик ошибок) могли его обнаружить? Простейший подход — генерация исключения “предусловие нарушено”, но если >f объявлена как >noexcept, это может быть невозможным; генерация исключения приведет к завершению программы. По этой причине разработчики библиотек, различающие широкие и узкие контракты, в общем случае резервируют >noexcept для функций с широкими контрактами.

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

>void setup(); // Функции, определенные в другом месте

>void cleanup();


>void doWork() noexcept {

> setup();     // Настройка для выполнения некоторой работы

> …            // Выполнение работы

> cleanup();   // Очистка после выполнения работы

>}

Здесь функция >doWork объявлена как >noexcept, несмотря на то, что она вызывает функции >setup и >cleanup без такого модификатора. Это кажется противоречием, но ведь может быть так, что функции >setup и >cleanup документированы как не генерирующие исключений, пусть при этом они и не объявлены как >noexcept. Для такого их объявления могут иметься некоторые веские причины. Например, они могут быть частью библиотеки, написанной на языке программирования С. (Даже у функций стандартной библиотеки С, перемещенных в пространство имен >std, отсутствуют спецификации исключений; например, >std::strlen не объявлена как >noexcept.) Они также могут быть частью стандартной библиотеки С++98, в которой решено не использовать спецификации исключений С++98 и которая еще не пересмотрена на предмет использования возможностей С++11.

Поскольку для функций, объявленных как >noexcept, имеются законные основания полагаться на код, не имеющий гарантии


Еще от автора Скотт Мейерс
Эффективное использование STL

В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.


Как функции, не являющиеся методами, улучшают инкапсуляцию

Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Платформа J2Me

Эта книга научит вас, как разрабатывать программное обеспечение для платформы J2ME компании «Sun Microsystems». Эта книга придерживается стиля учебного пособия, это не справочное руководство.Цель — дать вам твердую основу в понятиях и техниках, которая даст вам возможность решиться на самостоятельную разработку качественных приложений.


Виртуальная библиотека Delphi

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


Обработка баз данных на Visual Basic.NET

Это практическое руководство разработчика программного обеспечения на Visual Basic .NET и ADO.NET, предназначенное для создания приложений баз данных на основе WinForms, Web-форм и Web-служб. В книге описываются практические способы решения задач доступа к данным, с которыми сталкиваются разработчики на Visual Basic .NET в своей повседневной деятельности. Книга начинается с основных сведений о создании баз данных, использовании языка структурированных запросов SQL и системы управления базами данных Microsoft SQL Server 2000.


Исчерпывающее руководство по написанию всплывающих подсказок

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


Программное обеспечение встроенных систем. Общие требования к разработке и документированию

Embedded system software. General requirements for development and documentationСтандарт подготовлен в развитие ГОСТ Р ИСО/МЭК 12207-99 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.