Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 21
Текст из файла (страница 21)
Это нежелательно, и поэтому в следующих разделах я буду использовать контейнер Уес — простую адаптацию класса яес(ог, проверяющую, попадает ли индекс в допустимый диапазон значений. Тип Уес во всем эквивалентен типу вес(ог, но он генерирует исключение типа оп( о1 галле [определенное в файле <я((гехсер(>), когда индекс выходит за границы допустимого диапазона. Технологии создания типов, подобных Уес, и эффективного использования исключений рассматриваются в 911.12, 98.3, главе 14 и Приложении Е.
Однако для иллюстрирующих примеров в настоящей книге вполне достаточно следующего определения; (етр(а(е<с!азя Т> с(аяя Уес: риЫ(с чес(ос< Т> ( риЬВс: Уес (): чес(ос< Т> () ( ) Уес (т( я): чес(ог<Т> (я) ( ) Тя орега(ог [ ) ((н( () ( ге(игп а((() ( ) д' с проверкой диапазона сопя( Тя прего(ог [ ) (т( () сонм ( ге(игп а((() ( 1 й' с проверкой диапазона )( Для доступа к элементам векторов по индексу класс чес(ог определяет функцию а((), генерирующую исключение типа оп( о1 галле при выходе индекса за границы допустимого диапазона 616.3.3). При необходимости, доступ к базовому типу яес(ос< 7> может быть заблокирован; см.
915.3.2. Возвращаясь к задаче о хранении имен и телефонных номеров, мы можем теперь смело применить класс Уес, будучи полностью уверенными в том, что выход индексов за границу допустимого диапазона будет надежно перехвачен. Например: 95 3.7. Контейнеры Мес<Еп«у> рйопе Ьоой (1000) г( используем как раньше ю(((рпп( епиу(йп(() ( сот«рйопе Ьоой(() .пате«' '«рйопе Ьоой(().питЬег«' ~п'; Выход индекса за границу допустимого диапазона вызовет генерацию исключения, которое пользователь может перехватить.
Например; гоЫ1'( ) ( «у ( 1ог((п((=0; рс!0000; (ье) рпп( еппу (() ) са(сй (ош оз гапяе) ( сои(«ь галде еггог~ и "; ) ) Исключение будет сгенерировано и перехвачено при попытке вычисления выражения рйопе Ьоой(() в момент, когда выполнится условие ( ==1000. Если пользователь не перехватит это исключение, программа будет принудительно снята с выполнения стандартным образом, а не продолжит выполнение с непредсказуемыми последствиями. Для минимизации сюрпризов, связанных с исключениями, в качестве тела стартовой функции гпай(() можно использовать «у-блок: и(( (пап( ( ) о'еаш код са(сй (ои( о1 гапяе) ( сегг«" гапяе еггог~пп; ) са(сй (... ) ( сегг«ьипйпопп ексерйоп сйгошп',пь( ) Если мы не перехватим исключение, связанное с выходом за границу допустимого диапазона индексов, или иные исключения, то сообщение об ошибке будет записано в стандартный поток ошибок сегг Я21.2.1).
3.7.3. Контейнер 11вт Включение новых абонентов в телефонный справочник и удаление из него ненужных записей являются распространенными операциями. Из-за этого, для телефонного справочника больше подходит список (1(йж), а не вектор. Например: ((мсЕппу> рйопе Ьоой( Глава 3. Обзор стандартной библиотеки Если мы используем список, то лишаемся доступа к элементам по индексу. Вместо этого, мы осуществляем поиск элемента с заданным значением.
При этом мы опираемся на идею о представлении контейнеров в виде последовательности элементов (см. в3.8): го/й ринг епоу(сопи вййпяй з) ( гурейе/ 11зг <Ел!ту>:: сопя! Ьегагог 1.1 ! !ог (И 1=рволе Ьоой. Ьеа/п ( ); 1 ! = рйопе Ьоой. елй ( ); »»1) сопи Епггуь е = *й (у (в= =в. пате) ( сои!«е.
пате« ' ' «е. питЬег« ' ч,п '; ге!и л; ) ) // ссылка используется ради краткости записи Поиск строки з начинается с начала списка и продолжается либо до ее обнаружения в некотором элементе, либо завершается достижением конца списка. Любой контейнер стандартной библиотеки предоставляет функции Ьея!и() и епйн, возвращающие итераторы, которые настроены, соответственно, на первый элемент и на элемент, следующий еза последним» (516.3.2).
Если итератор !ссылается на некоторый элемент контейнера, то +»! ссылается на следующий элемент. Доступ к элементам контейнера осуществляется с помощью выражения вб Пользователям нет необходимости знать точный тип итераторов стандартных контейнеров. Тип итератора определяется в рамках определения контейнера и на него можно ссылаться по имени. Когда не нужно модифицировать элементы контейнера, целесообразно использовать итераторы типа сопи 1ге«агог. В противном случае нужно применять итераторы типа !ге«а!о« (в16.3.1). Добавлять элементы к списку и удалять их из него очень просто: го(й Г" (сопят Елоуа е, 11зт<Елггу>:: йегагог 1, 11зт<Елйу>:: йегатог р) рьопе Ьоой.рияд !гоп! (е); // добавить в начало рйопе Ьоой.риза Ьасй(е); //добавит~ в конец рйоле Ьоой.
1пзег((1, е); // добавить перед элементом, указуемым через 1 ж удалить элемент, указуемый через р Рйопе Ьоой. егазе (р); ) Детальное описание функций 1пвегг() и егазе() дано в 516.3.6. 3.7.4. Контейнер )ттар Писать программы для поиска имен в списках пар значений (имя, номер телефона) довольно утомительно. Кроме того, последовательный поиск эффективен лишь для коротких списков. В то же время, существуют специальные структуры данных, которые напрямую поддерживают внедрение элементов, их удаление и поиск по значению. В стандартной библиотеке, например, имеется контейнерный тип 3.7.
Контейнеры тар (э17.4.1). Тип тар является контейнером для хранения пар величин. Напри- мер: тор<тану, (и(> рлоне Ьооа( Тип тар часто назгявают ассоциативным массивом (атос!айте оп ау) или словарем (а((с((влагу). Будучи индексирован по значению его первого типа (называемого ключом— lсеу), тар возвращает соответствующее значение его второго типа (называемого просто значением или отображаемым тином — га(ие или тарре(1 (уре). Например: юоЫ рнн( ен(гу (сон(( в(г(ндь в) Ц'(т(('=рлоне Ьооа(в] ) сои(«в«' '«(«''~н' ( ) Если вхождение ключа в не обнаружено, возвращается некоторое значение «по умолчанию».
Для целочисленных типов данных в контейнерах типа тар таковым служит нуль. А в нашем случае нуль не является допустимым телефонным номером. 3.7.5. Контейнеры стандартной библиотеки Контейнеры типов тар, Нв( и вес(ог могут использоваться для представления телефонной книги. У каждого из них есть свои сильные и слабые стороны. Например, индексирование векторов является простой и эффективной операцией, Но с другой стороны, внедрение элемента между существующими элементами вектора — весьма затратная операция.
Для списков ситуация во всем противоположная. Ассоциативный массив (тар) подобен списку нар (ключ, значение), но он оптимизирован под поиск значений по заданному ключу. В стандартной библиотеке реализовано множество полезных типов контейнеров, из которых программист всегда может выбрать тот, который больше всего подходит к особенностям конкретной задачи: Глава 3. Обзор стандартной библиотеки Подробнее стандартные контейнеры рассматриваются в 5!6.2, 516.3 и главе 17.
Они объявляются в пространстве имен тй и реализуются в заголовочных файлах <гесгог>, <11яг>, <тар> и так далее (~16.2). Стандартные контейнеры и их базовые операции разрабатывались так, чтобы с понятийной точки зрения они были очевидными. Более того, одни и те же операции для разных контейнеров имеют один и тот же смысл. В общем случае, базовые операции применимы ко всем типам контейнеров. Например, операция рияЬ Ьаей() может использоваться (с разумной эффективностью) для добавления элементов в конец векторов и списков, а операция я1ее() сообщает количество элементов для любого контейнера. Такая выразительная и семантическая однородность помогает программистам создавать новые типы контейнеров, которые можно использовать так же, как и стандартные типы контейнеров.
Примером может служить рассмотренный выше тип гес (53.7.2), проверяющий допустимость значений индексов. В главе 17 будет рассмотрен контейнерный тип Ьаяй тар. Однородность контейнерных интерфейсов позволяет разрабатывать алгоритмы независимо от конкретных типов контейнеров. 3.8. Алгоритмы Структуры данных, вроде списка или вектора, сами по себе не очень-то и полезны. Чтобы их можно было использовать, требуются такие базовые операции, как добавление и удаление элементов. Более того, мы редко используем контейнеры исключительно с целью хранения объектов. Чаще всего, мы объекты сортируем, печатаем, удаляем, извлекаем их подмножества, выполняем поиск и т.д.