Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 237
Текст из файла (страница 237)
Нужно уничтожить элемент, удаленный из контейнера. 3. Под новый элемент требуется выделить память. 4. Элементы чес(ог или г(ев(це нужно переместить в новое место в памяти. 5. Ассоциативные контейнеры вызывают операции сравнения для элементов. б.
Вставки и удаления включают операции с итераторами. 1100 Приложение Е Исключения и безопасность стандартной библиотеки В каждом из перечисленных случаев могут генерироваться исключения. Если деструктор генерирует исключение, не дается вообще никаких гарантий (ЬЕ.2), так как в этом случае они обошлись бы непозволительно дорого. Но от генерации исключений другими операциями, предоставляемыми пользователем, библиотека защищает и себя, и своих пользователей. При манипуляциях со связными структурами данных, вроде!пг или отар, элементы могут добавляться или удаляться, не оказывая влияния на другие элементы этих контейнеров. Иначе обстоит дело для контейнеров вроде яестог или Неуие, элементы которых распределены в памяти непрерывно; здесь иногда приходится перемещать элементы на новые места.
Дополнительно к базовой гарантии стандартная библиотека предоставляет сильную гарантию для нескольких операций, вставляющих и удаляющих элементы. Поскольку контейнеры, реализованные в виде связных структур данных, ведут себя иначе, чем контейнеры с непрерывным размещением элементов в памяти, стандарт обеспечивает слегка различающиеся гарантии для разных видов контейнеров: 1. Гарантии лля контейнеров гесты (516.3) и Ыеаие (017.2.3): ° Если исключение генерируется в функциях ризЬ Ьаей() или ризЬ )тоаг(), то они оставляют контейнер нетронутым. ° Если исключение генерируется в функции (азегтО, но не копирующим конструктором или операцией присваивания типа элемента, то контейнер остается нетронутым.
° Функция еказе() не генерирует исключений, кроме случаев возникновения исключений в копирующем конструкторе или в операции присваивания типа элемента. ° Функции рор ЬасЬО и рор Геоат() не генерируют исключений. 2. Гарантии для контейнера!!зт (917.2.2): ° Если исключение генерируется в функциях ризЬ Ьаей() или ризЬ ггоатО, то они оставляют контейнер нетронутым. ° Если исключение генерируется в функции тазегтО, то контейнер остается нетронутым. ° Функции егазе(), рор Ьасй(), рор /тоатО, зр(тее() и зезеезе() не генерируют исключений. ° Функции-члены контейнера 1мт, такие как геаюзе(), гетаозе т7(), иащие(), золт() и «текле(), не генерируют исключений, кроме случаев возникновения исключений в предикате или функции сравнения. 3.
Гарантии для ассоциативных контейнеров (517.4): ° Если исключение генерируется операцией (азезт() при вставке единственного элемента, то контейнер остается нетронутым. ° Функция егазе() не генерирует исключений Обратите внимание, что если для операций на контейнере дается строгая гарантия, то при генерации исключения все итераторы, указатели и ссылки на элементы остаются действительными.
Е 4. Гарантии стандартных контейнеров 1101 Эти правила могут быль объединены в таблицу: Гарантии операций контейнеров ра( аеоие геетог иыр не генерирует (копирование) не генерирует (копирование) не генерирует не генерирует не генерирует (копирование) не генерирует (копирование) не генерирует не генерирует сильная ~ сильная (копирование) сильная (копирование) сильная базовая сильная сильная ) сильная (копирование) (копирование) ) не генерирует (сравнение) сильная сильная сильная сильная 'дрор вися () не генерирует не генерирует не генерирует ) рор (гоит() не генерирует не генерирует гегиоге ( ) не генерирует (сравнение) ) гегиоге (Г() не генерирует (предикат) гегегее ( ) не генерирует не генерирует- не генерирует' ,не генерирует , енир() не генерирует не генерирует (копир-е сравнения) иийтие() не генерирует (сравнение) Где гарантия требует отсутствия исключений в некоторой пользовательской операции, там эта операция указана в круглых скобках под строкой гарантии.
Эти требования точно сформулированы в тексте, предшествующем таблице. Функции виар() отличаются от других упомянутых функций тем, что не являются функциями-членами. Гарантия для с!еаг() вытекает из таковой для егазе() Я!6.3.6). В таблице перечислены гарантии, предоставляемые в дополнение к базовой гарантии. Поэтому в таблицу не вошли такие операции, как гегегзе() и иа!аие() для гесгог, поскольку они предоставляются как алгоритмы для любых последовательностей без дополнительных гарантий. «Почти контейнер» Ьав!с зтг!ий ($17.5, 020.3) предоставляет базовую гарантию для всех операций. Стандарт также гарантирует, что егазе ( ) и заир ( ) для этого типа не генерируют исключений, и что на функции !иеегг() и ризЬ Ьасй() распространяется сильная гарантия. Приложение Е.
Исключения и безопасность стандартной библиотеки 1102 Помимо неизменности контейнера, операция, предоставляюшая сильную гарантию, также оставляет действительными все итераторы, указатели и ссьики. Например: ко(д прелате (тор<в!к!па, Х> ь т, тар<тгтл, Х>:: йегагог сиггепг) ( Хх; згг(ие Ят и Ыге (сги»з»х) згу ( вигген! = т.гпзегз(сиггеп<,тале ра(г(з,х) ); ) сагой (... ) ( У здесь вигген! по-презснеиу соответствует текущему элементу Е.4.2. Гарантии и компромиссы зоЫ Г(ггзз<Х>ь Ьг, весгог<Х>ь вес, сопзг Хь х) ( ( Ь!.риза Ьасй(х) ) сагой (... ) ( I! (з! не изменился ге!ига г ~У добавляем элемент к йз( ггу ( вес.ризй Ьасй(х); ) сагой (...
) ( ~У вес не изменился !! добавляем элемент к кестог Затейливая смесь дополнительных гарантий отражает сушность реализации. Программисты предпочитают сильную гарантию с возможно меньшим числом оговорок, но они же настаивают, чтобы каждая операция стандартной библиотеки была как можно более эффективна. Оба пожелания разумны, но для многих операций невозможно удовлетворить их одновременно. Чтобы дать лучшее представление о компромиссах, я исследую способы добавления единственного или нескольких элементов к контейнерам (Ьг, вестог и тар.
Рассмотрим сначала добавление единственного элемента к !(и или весгог. Как всегда, ризй Ьасй () обеспечивает простейший способ для этого; Е4. Гарантии стандартных контейнеров 1103 ге!игл; ) р й( и гес получили ло новому элементу со значением х ) Обеспечение сильной гарантии в таких случаях дается легко и дешево. Она весьма полезна, поскольку представляет собой полностью безопасный в контексте исключений способ добавления элементов. Однако ривй Ьасй() не определяется для ассоциативных контейнеров — у контейнера шар отсутствует Ьасй() . В конце концов, последний элемент ассоциативного контейнера определяется отношением порядка, а не позицией.
Гарантии для )изегг() несколько более сложные. Причина состоит в том, что иногда функции йхтеггО нужно помешать элемент куда-то в «середину контейнера». Это не проблема для связанных структур данных, таких как ))зг или итар. В то же время, при наличии свободного зарезервированного пространства у контейнера типа гесгог, очевидная реализация уесгог<Х>::)пзеи() копирует элементы, расположенные после точки вставки, чтобы освободить место.
Это эффективнЬ, но нет простого способа восстановления гесгог, если копирующий конструктор типа Хили его операция присваивания генерируют исключение (см. 5Е.8!)О-! !)). Следовательно, уесгог обеспечивает гарантию лишь при условии, что.копирующие операции элементов не генерируют исключений.
А контейнеры йлт и «тар не нуждаются в этом условии; они могут запросто привязать новые элементы уже после выполнения любого копирования. Для примера предположим, что копирующие операции типа Х генерируют исключение Хксаппо( сору, если не получается успешно создать копию: гоЫЯ)гзг<Х>а тзг, гестог<Х>ь вес, тор<э!с(пе,Х>ь и, сопл! Хь х, сопл! в!с!лев з) ( ау ( )з!. гпзегт (гз!. Ьеегл (), х); ~У добавляем элемент к йм ) савей (... ) ( !! йт не изменился ге!игл; ) лу ( гес.гпзегг(гес.йее!л(),х]; (гдобавляем элемент к вес(ог ) сагой (Х:: санно! сору) ( Р оорз: гес может содержать, а может и не содержать новый элемент ге!игл; ) са!сй (... ) ( У вес не изменился 1104 Приложение Е Исключения и безопасность стандартной библиотеки гетигп т ) тгу ( т.гпзегт(тайе ра1г(з,х) ); сУ добавляем элемент к тар ) сатсЬ (...
) ( УУ т не изменился гетигп т ) У (зт и чес получили по новому элементу со значением х УУ т получил элемент со значением (Лх) ) Если исключение Х:: спппог сору перехвачено, то в этот момент новый элемент либо уже вставлен в гес, либо не вставлен. В первом случае объект находится в действительном состоянии, но каково его значение — неизвестно. Возможно, что после генерации исключения Х:: саппог сору некоторый элемент окажется мистическим образом продублированным (см.