Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 238
Текст из файла (страница 238)
Кроме того люоая функция, которая (прямо илн косвенно) распределяет память, может сгенерировать исключение, указывающее на исчерпание памяти (как правило, зИсЬас( а((ос). Д.5Л. Строки Операции со строками з(г1ад' могут генерировать самые разнообразные исключения. Однако Ьаз(с зЫпй манипулирует своими символами через функции, предоставленные сйаг 1гаИз (В 20.2), а этим функциям не позволено генерировать исключения.
Тоесть сйаг 1гаЫз, предоставленный стандартной библиотекой, нс генерирует исключений, но никаких гарантий не дается на случай, если операция определенного пользователем сЛаг (га(1з генерирует исключение. В частности обратите внимание, что типу„используемому как элементный (символьный) тип для Ьаз1с згппьг, не дозволено иметь определяемый пользователем копирующий конструктор или определяемое пользователем копирующее присваивание. Тем самым мы избавляемся от важного возможного источника исключений. Класс Ьаз1с з1г1щ очень похож на стандартный контейнер Я 17.5, э 20.3). В самом деле, его элементы составляют последовательность, к которой можно обращаться с помощью Ьаз!с з1гтй<СЬ, Тг, А>;з1ега1ог и Ьаз(с з1г(па<СЬ, Тг, А ссопз1 Иега1ог. Соответственно, реализация строки предлагает основную гарантию Я Д.2), а гарантии для егазе)), (лаем, ризЬ Ьасй)) и зшар)) (~ Д.4,1) относятся и к Ьаз1с з1гтй.
Например, Ьаз1с з1гтд<СЬ,ТгА>сризй Ьасй)) обеспечивает сильную гарантию. Д.5.2. Потоки Если требуется, функции 1оз1геат генерируют исключения, чтобы сообщить об изменениях состояния (ч 21.3.6). Соответствующая семантика хорошо определена и не созлает трудностей по части бсзопасности исключений. Генерация исключения пользовательскими орега1ог«)) или орега1ог»)) для самого пользователя может выглядеть так, словно исключение сгенерировала библиотека 1оз1геат.
Однако та- 1048 Приложение Д. Безопасность исключений и стандартная библиотека кое исключение не повлияет на состояние потока Я 21,3.3). Дальнейшие операции потока быть может !л не найдут ожидаемых данных — потому что предыдущая опера.
ция сгенерировала исключение вместо нормального завершения — но сам по себе поток не повреждается. Как всегда при возник!лове!чин проблем ввода/вывода, перед продолжением чтения или записи может потребоваться вызов с1еаг() Я 21.33, ф 21.3.5). Подобно Ьаз!с з!г!пд, при манипуляциях с символами потоки !оз!геат полагаются на сйаг !га1!з Я 20.2.1, () Д.5.1). Таким образом реализация может предполагать, что операции с символами не генерируют исключений, и не дается никакллх гарантий, если пользователь нарушает это предположение.
Чтобы сделать возможной значительную оптимизацию кода, предполагается что классы 1оса1е (() Г.2) и Гасе! Я Г.З) не генерируют исключснллй. Если бы они генерировали, использующий их поток мог бы повредиться. В то же время наиболее вероятноеисключение,зИсбад саз!изизе Гасе!(~ Г.3.1),можетсгенерироватьсятольков предоставленном пользователем коде вне стандартной реализации потока. В хулшем случае это приведет к неполному выводу или неудачному чтению, но не к повреждению самого потока озтгеат (или!зтгеат).
Д.5.3. Алгоритмы Кромсая!и!!1а!!хек сору(), ип!пШа1!вел( Я!!(), и ип1п!!!а1(хе!1 Я1 п()(ф ДАА), стандарт предлагает для алгоритмов только основную гарантию Я Д.2). То есть при условии, что предоставленные пользователем объекты ведут себя корректно, алгоритмы соблюдают все инварианты стандартной библиотеки и не приводят к утечке ресурсов.
Чтобы избежать неопределенного поведения, предоставленныс пользователем операции должны всегда оставлять свои операнды в действительных состояниях, а деструкторы це должны генерировать исключений. Сами алгоритмы не генерируют исключений. Вместо этого они сообщают об ошибках и сбоях через свои возвращаемые значения. Например поисковые алгоритмы в качестве сообщения «не найдено» обычно возвращают конец последовательности (ч 18.2). Таким образом исключения, сгенерированные в стандартных алгоритмах, на самом деле возникают в предоставленной пользователем операции.
Эти исключения происходят либо в операции на элементе, такой как предикат Я 18А), присваивание или яшар(), либо в распределителе памяти Я 19А). Если подобная операция генерирует исключение, алгоритм немедленно завершается, а обработка исключения остается на совести тех функций, которые вызвали алгоритм. Некоторые алгоритмы допускают генерацию исключения, когда контейнер находится в плохом с точки зрения пользователя состоянии.
Так ряд алгоритмов сортировки временно копируют элементы в буфер и позже возврашают их обратно в контейнер. Такой зог1() мог бы скопировать элементы из контейнера (планируя записать их назад в надлежащем порядке позже), начать записывать что-то поверх них, а затем сгенерировать исключение. С точки зрения пользователя, контейнер испорчен. Однако все элементы находятся в действительном состоянии, так что восстановление должно быть довольно прямолинейным. Обратите внимание, что стандартные алгоритмы обращаются к последовательностям через итераторы, То есть стандартные алгоритмы никогда не работают с контейнерами непосредственно, только с элементами контейнеров. То, что стандартный ал- 1049 Д.б. Значение для пользователей библиотеки горитм никогда непосредственно не добавляет и не удаляет элементы из контейнера, упрощает анализ последствий исключений.
Точно так же, если к структуре данных обращаются только через итераторы, указатели и ссылки ца сопзг 1например, через сопзг пес*), обычно тривиально проверяется, что исключение нс вызывает никаких нежелательных эффектов. Д.5.4. )га(аггау и Совр(ех Числовые функции явно не генерируют исключений 1глава 22). Однако оа1аггау должен распределить память и, значит, может сгенерировать зЫсЬаа айос. Кроме того, шаблонам иа1аггау и сотр1ех можно передать тип элементов 1скалярный тип), который генерирует исключения. Как всегда, стандартная библиотека обеспечивает основную гарантию Я Д.2), но никаких особых гарантий не дается относительно результатов вычисления, завершившегося исключением. Подобно ЬазГс зГппу Я Д.5.1), классам эа1аггау и сотр1ех разреп1ается полагать, что у типа аргумента их шаблона нет определенных пользователем операций копирования, так что допустимо побитное копирование.
Как правило, эти числовые типы стандартной библиотеки оптимизированы по быстродействию в прсдположении, что тип их элементов 1скалярный тип) не генерирует исключений. Д.5.5. Стандартная библиотека Си Операция стандартной библиотеки без спецификации исключений может генерировать исключения определяемым реализацией способом. С другой стороны, функции стандартной библиотеки Си не генерируют исключений, если у них нет параметра- функции, которая генерирует.
Ведь функции — часть Си, а в Си нет исключений. Реализация вправе объявить стандартные функции Си с пустой спецификацией исключений гйгош(), чтобы помочь компилятору сгенерировать лучший код. Функции типа дзогт() и Ьзеагсй() Я 18.11) принимают в качестве аргумента указатель на функцию. Поэтому они могут сгенерировать исключение, если это делают их параметры. Основная гарантия Гб Д.2) распространяется и на эти функции. Д.б. Значение для пользователей библиотеки На безопасность исключений в контексте стандартной библиотеки можно смотреть так; у нас не будет никаких проблем, если мы не создадим их на собственную голову.
Библиотека будет функционировать правильно, пока предоставленные пользователем операции удовлетворяют основным требованиям стандартной библиотеки Я Д.2). В частности исключение, сгенерированное операцией стандартного контейнера, не вызовет утечки памяти из контейнера и не оставит контейнер в недействительном состоянии. Таким образом, перед пользователем библиотеки стоит следующий вопрос: как мпе определить свои типы таким образом, чтобы они не вызвали неопределенного поведения или утечки ресурсов? Вот основные правила: [1] При модификации объекта не уничтожайте его старое представление до того, как полностью будет создано новое представление и оно сможет заменить старое без риска исключений.
Например, см. реализацию эесгогцорегагог=(), ваге аэзГдл() и эесГогсризЬ Ьаск() в й Д.З. 1050 Приложение Д. Безопасность исключений и стандартная библиотека [2] Перед генерацией исклсочения освободите все захваченные ресурсы, которые не принадлежат какому-нибудь (другому) объекту. [2а] Методика «выделение ресурса есть инициализация» (ч 14.4) и правило языка, что частично созданные объекты уничтожаются в той степени, в какой они были созданы Я 14А.1), могут быть здесь наиболее полезны.
Например, см. 1еай[] в ~ Д.2. [26] Алгоритм ип1п1йа1тес( сору[[ и сто собратья обеспечивают автоматическое освобождение ресурсов при невозможности завершить создание набора объектов (б Д.4А). [3] Перед генерацией исключения удостоверьтесь, что каждый операнд находится в действительном состоянии. То есть оставляйте каждый обьект в состоянии, которос позволяет обратиться к нему и уничтожить его, не вызвав неопределенного поведения и генерации исключения из деструктора, Например, см. присваивание оес1ог в 5 Д.3.2.