|
Программирование >> Операторы преобразования типа
Обработка исключений стала одним из последних вопросов, обсуждавшихся в процессе стандартизации. Найти хорошее решение оказалось нелегко. На это понадобилось много времени, что объяснялось двумя основными причинами. О Было очень трудно определить, какую степень безопасности должна обеспечивать стандартная библиотека С++. Напрашивается мысль, что всегда следует обеспечивать максимальный уровень из всех возможных. Например, можно потребовать, чтобы вставка нового элемента в произвольной позиции вектора либо завершалась успешно, либо не вносила изменений. Однако исключение может произойти в процессе копирования элементов, расположенных после позиции вставки, на следующую позицию для освобождения места под новый элемент; в этом случае полное восстановление невозможно. Чтобы добиться указанной цели, вставку пришлось бы реализовать с копированием всех элементов вектора в новую область памяти, что серьезно отразилось бы на быстродействии. Если приоритетной задачей проектирования является высокое быстродействие (как в случае STL), обеспечить идеальную обработку исключений для всех возможных ситуаций все равно не удастся. Приходится искать компромисс между безопасностью и скоростью работы. О Многие беспокоились о том, что присутствие кода обработки исключений отрицательно скажется на быстродействии. Это противоречило бы главной цели проектирования - обеспечению максимального быстродействия. Впрочем, разработчики компиляторов утверждают, что в принципе обработка исключений реализуется без сколько-нибудь заметного снижения быстродействия (причем такие реализации уже существуют). Несомненно, лучше иметь гарантированные четко определенные правила обработки исключений без заметного снижения быстродействрш, чем рисковать системными сбоями из-за исключений. В результате этих обсуждений стандартная библиотека С++ теперь предоставляет базовую гарантию безопасности исключений: возникновение исключений в стандартной библиотеке C-I-+ не приводит к утечке ресурсов или нарушению контейнерных инвариантов. К сожалению, во многих случаях этого недостаточно. Довольно часто требуется более твердая гарантия того, что при возникновении исключения произойдет возврат к состоянию, имевшему место перед началом операции. О таких операциях говорят как об атомарных по отношению к исключениям, а если воспользоваться терминологаей баз данных, можно сказать, что эти операции должны обеспечивать возможность либо принятия, либо отката, то есть тратакционную безопасность. В том, что касается этих требований, стандартная биб.нютека С++ теперь гарантирует две вещи. О Для всех узловых контейнеров (списки, множества, мультимножества, отображения и мультиотображения) неудачная попытка создания узла просто оставляет контейнер в прежнем состоянии. Более того, удаление узла не может завершиться неудачей (если исключение не произойдет в деструкторе). Однако при вставке нескольких элементов в ассоциативный контейнер из-за необходимости сохранения порядка сортировки обеспечивать полное восстанов.;1ение Спасибо Дейву Абрахамсу (Dave Abrahams) и Грегу Колвипу (Greg Colviu) за их работу в области безопасности исключений в стандарте С++, а также за информацию, полученную от HVIX ни этой теме. было бы непрактично. Таким образом, только одноэлементная вставка в ассоциативные контейнеры обеспечивает транзакционнуго безопасность (то есть либо завершается успешно, либо не вносит изменений). Кроме того, гарантируется, что все операции удаления (как одного, так и нескольких элементов) всегда завершаются успешно. Для списков даже вставка нескольких элементов обладает транзакционной безопасностью. Более того, любые операции со списками, кроме renriove(), remove if(), nrierge(), sort() и uniqueQ, либо завершаются успешно, либо не вносят изменений. Для некоторых из перечисленных операций стандартная библиотека С++ предоставляет условные гарантии (см. с. 180). Отсюда можно сделать вывод: если вам требуется контейнер, обладающий транзакционной безопасностью, выбирайте список. О Контейнеры на базе массивов (векторы и деки) не обеспечивают полного восстановления при вставке элементов. Для этого пришлось бы копировать все элементы, находящиеся за позицией вставки, а на обеспечение полного восстановления для всех операций копирования ушло бы слишком много времени. Тем не менее операции присоединения и удаления элементов в конце контейнера не требуют копирования существующих элементов, поэтому при возникновении исключений гарантируется откат (возвращение к прежнему состоянию). Более того, если элементы относятся к типу, у которого операции копирования (копирующий конструктор и оператор присваивания) не генерируют исключений, то любые операции с этими элементами либо завершаются успешно, либо не вносят изменений. Более подробный перечень всех контейнерных операций, обеспечивающих в отношении исключений более твердые гарантии, приведен на с. 254. Учтите, что все гарантии основаны на запрете исключений в деструкторах (который в С++ должен выполняться всегда). Стандартная библиотека С ++ соблюдает это требование; его должны соблюдать и прикладные программисты. Если вам понадобится контейнер с полными гарантиями транзакционной безопасности, используйте либо список (без вызова функций sort() и unique()), либо ассоциативный контейнер (без вызова многоэлементных операций вставки). Тогда вам не придется создавать копии данных перед модификацией, чтобы предотвратить возможную потерю данных. Копирование контейнеров иногда обходится очень дорого. Если вы не используете узловой контейнер, но нуждаетесь в полноценной тюддержке транзакционной безопасности, для всех критических операций придется делать промежуточные копии данных. Например, следующая функция обеспечивает почти безопасную вставку значения в заданную позицию произвольного контейнера: template <class Т. class Cont, class Iter> void Insert CCont& coll. const IterS pos, const T& value) Cont tmp(coll); Копирование контейнера со всеми элементами tmp.lnsertCpos.value); Модификация копии coll.swapCtmp); Использование копии (если модификация } выполнена без исключений) Почти означает, что эта функция не идеальна. Дело в том, что функция swapO тоже может генерировать псключсннс, если оно имеет место в критерии сравнения ассоциативного контейнера. Как видите, безупречная обработка исключений - дело весьма непростое. Расширение STL Библиотека STL проектировалась с расчетом на возможность расширения практически в любом направлении. Программист может создавать и использовать собственные контейнеры, итераторы, алгоритмы и объекты функций, удовлетво-ряюшие определенным требованиям. Кроме того, в стандартной библиотеке С-Ы-не поддерживаются некоторые полезные возможности, поскольку в какой-то момент комитет по стандартизации был вынужден прекратить прием новых предложений и сосредоточиться на приведении в порядок того, что есть; иначе работа продолжалась бы до бесконечности. Самое заметное упущение в STL - отсутствие такого типа контейнера, как хэш-таблица. Просто предложение о включении хэш-таблиц в стандартную библиотеку С++ поступило слишком поздно. Тем не менее весьма вероятно, что новые версии стандарта будут содержать те или иные формы хэшей. Большинство реализаций библиотеки С++ уже содержат хэш-контейнеры, но, к сожалению, все они реализованы по-разному. За дополнительной информацией обращайтесь на с. 225. Среди других полезных расширений стоит отметить дополнительные объекты функций (см. с. 313), итераторы (см. с. 291), контейнеры (см. с. 221) и алгоритмы (см. с. 289).
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |