Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 121
Текст из файла (страница 121)
Контейнер пзы)1(пзар Контейнер ти!!!шар похож на тар [ассоциативный массив), если не считать, что он позволяет дублировать ключи: 1етр1а1е с(аяя Кеу, с!аяк Т, с(азз Стр = (екк<Кеу>, с!азк А = а Носа!ог -ра!с <сопя! Кеу, Т» > с1 аз к кЫ< ти111т ар ( риЬ1!и // как и тар, эа иалюченяехк !1ега1ог!пзег) (сопя!па)ие !ура //воэврап!ает шпервтор, не пару //нет оператора индексации [] ); Например (используя Сяугту (еяя нз 9 17.1А.1 для сравнения С-строк): ооЫЯпар<сйат, (п1, СяРту 1езк>о т, та!!!тир<клас<, т1, Ся1ппу 1екя>ь тт) ( тхизег1(тауе раи.
("х',4)); т !пкег1 (таус раи. ("х", Ь)); // теперь т["х"] == 4 //эффектанеинеет ужеестьэаписьдяях(у !74.!.7) лнпхлкег1 Ьпауе ра!г ("х,4)); ттхляеП(тауе ра!г("Х, 3; // теперь тт содержит и ! х", 4) и !"х", Ь) Это приводит к тому, что та!1!шар не может поддерживать индексацию по зна кению ключа, как зто делает тар.
Операции едиа! гатще (), !ошег Ьоипс[ () и иррег Ьоип<1 () Я 17 А.1.6) являются первичными средствами доступа к нескольким значениягп с одним и тем же ключом. Естественно, в тех случаях, когда может существовать несколько значений с одним и тем же ключом, ти111тар выглядит предпочтительнее тар. Это случается гораздо чаще, чем кажется, когда впервые слышишь о ти!1!тар. Кое в чем ти!1!тир даже совершеннее и изящнее тар.
Поскольку у человека запросто может быть несколько телефонных номеров, хорошим примером применения ти11(тар является телефонная книга. Я мог бы распечатать номера моих телефонов так: оо!д рп пг литЬегк (сопя! ти!!1тар< к!пну, т1>й рдопе Ьооу) ( 1урес/е~ти111тар< з!ппу, )п1>с сопи! Ыега1огТ; ра(г<7, 1> Ь = раопе Ьооу.еуиа! гапуе ( Страуструп"); 1ог (11 =Ь/)гз1,1!= Ьлесопд; +ь!) сои1 ((1).яесопс)«<,п'; В контейнере ти!1!шар аргумент операции !пзег1 () всегда вставляется. Следовательно, щи!1!тарх/пзег1 () возвращает итератор, а не пару ра/г<11ега1ог,боо!>. как в случае с тар.
Из соображений единообразия библиотека могла бы обеспечить универсалькую форму операции !пиес! () как для тар, так н для ти!1!тар, несмотря на то, что Ьоо( оказался бы для ти!1!тар лишним. Другое проектное решение 550 Глава 1?. Стандартные контейнеры обеспечило бы простую гпкег1 (), которая не возврапгала бы ЬооЕ в обоих случаях, н потом предоставляла бы пользователю тар каким-то образом выяснять, не вставлен лп ключ заново. Это тот случай, когда сталкиваются разные идеи по проектированию интерфейса. 17.4.3. Множества Множества можно рассматривать как ассоциативные массивы (() 174.1), в которых значения не играют роли, так что мьг отслеживаем только ключи. Это ведет лишь к неболыпим изменениям в пользовательском интерфейсе: 1етрЕа1е<с!азк Кеу, сЕияя Стр = Ееяя<Кеу>, сЕаязА = ауасагпг<Кеу» с1аяз яг<Е, зе1 [ риЬЕЕс: // кик тпр, зп исключениемг 1урег/е~Кеу эа1ие 1уре; О сач ключ нзлзетсл зничениел 1уре<Ее/Стр эа(ие сатраге; /! никпкик операпгароз ггндексиг!ии [) Определение о!г(ие Еуре как типа Ьеу Еуре — это хитрость, позволяющая программе, в которой используются множества и ассоциативные массивы, оставаться идентичной во многих случаях.
Отметим, что множества основываются на операции сравнения (по умолчанию <), а не равенства ( =). Это приводит к тому, что равенство элементов определяется неравенством (5 17,1А.1), и итерации по контейнеру ке1 имеют строго определенный порядок. Как и тар, класс ке1 предоставляет операторы ==, [=, <, >, <=, >- и функцию яшар (). 17.4.4. Контейнер пзи)1[ве1 Контейнер ти(1!ее! — это множество, допускающее одинаковые ключи: 1етрЕа!е<с1азяКеу, сЕаяя Стр = Еезя<Кеу>, сЕаязА = аупса1пг<Кеу» сЕаяя з1длтиЕИяе1 [ риЬЕгс.
// тпк зсе, как зе1, зи исключениемг Уел а1ог тяег1 (сопя! иа1ие 1урез4г // еозеригпиет ипгеригггор, а не пиру Операции едиа! галуа (), 1огиег Ьоип<Е() и иррег боинг(() (ф 1?А.16) — основные средства доступа к нескольким вхождениям ключа. 17.5. Почти контейнеры Е)строеныые массивы Я 5.2), строки к1г!пд (глава 20), массивы оаЕаггау Я 22А) и битовые наборьг ЬЕ!зе1 (ь 17.5.3) содержат элементы и, следовательно, во многих отношениях могут шгитаться контейнерами. Однако все они имеют те или иные недостатки в отношении стандартного контейнерного интерфейса, так что эти «почти контейнеры> не совсем взаимозаменяемы с полностью разработанными контейнерами, такими как вектора и списки.
17.5. Почти контейнеры 17.5.1. Строки Класс Ьаз1с з(г(пд'обеспечивает индексацию, итераторы с произвольным доступом и болыпинство удобных обозначений для контейнеров (глава 20). Однако Ьаз1с з1г(пу не предоставляет такого большого выбора типов элементов. Он оптимизирован для использования в качестве строки символов и, как правило, применяется совсем не так, как контейнеры. 17.5.2.
Ча1аиау Массив па1аггау Я 22.4) — это вектор, оптимизированный для численных вычислений, Следователыю, иа1аггау не претендует на то, чтобы быть универсальным контейнером. Класс па1аггау обеспечивает много полезных численных операций, однако из стандартных контейнерных операций Я 17.1.1) он предлагает только захе () и оператор индексации [1 Я 22А.2). Указатель на элемент массива па1аггау является итератором с произвольным доступом Я 19,2.1), 17.5.3. Битовые наборы Часто некоторые аспекты какой-либо системы, такие как состояние входного потока Я 21.3.3), представляются в качестве набора признаков («флюкков»), показывающих бинарные условия вроде «хорошо/плохо>, «правда/ложь> и «включено/ выключено».
Язык С++ эффективно поддерживает понятие небольших наборов признаков через битовые операции пад целыми числами Я 6,2А). Эти операции включают в себя Ъ (логическое И), ( (логическое ИЛИ), (исключающее ИЛИ), «(сдвиг влево) и» (сдвиг вправо). Класс-611зе1<М> обобщает это понятие и предлагает большие удобства, обеспечивая операции с набором из Мбит, индексированных от У до М вЂ” Е где Мизвестно во время компиляции. Для битовых наборов, не укладываюпц«хся в диапазон чисел типа 1опу 1п1, удобнее использовать 611зе1, чем оперировать непосредственно с числами.
Для наборов поменьше может быть как выигрьцп, так и проигрыш в эффективности. Если вы хотите задать битам имена, а пе нумеровать их, то альтернативой может быть использование множеств Я 17.4.1), перечислений Я 4.8) пли битовых полей Я В.8.1). Класс 611зе1<М> — это массив из М бит. Он отличается от эес1ог<Ьао1> Я 18.3.1.1) тем, что имеет фиксированную длину, а от множества Я 17А.3) — тем, что его биты проиндексированы целыми числами, а не ассоциативно — значениями. Кроме того, битовый набор обеспечивает операции для манипулирования битами. К одному биту невозможно обратиться прямо по встроенному указателю Я 3.1), поэтому Ь(йхе1 вводит тип, ссылающийся на бит. Это действительно универсально полезный прием для адресации объектов, для которых встроенный указатель по каким-то причинам не подходит: 1етр1а1е<зие 1Х>с1азз еЫ: Ь17ке1( ри61!с.
//ссылка на одиночный сит с1ааз ге/егеп се ( Хпепд с1азз Ь11хе1; ге/егспсе 0; 552 Глава 17. Стандартные контейнеры риЫ!а //Ь[!) относится к !гь!)-ну били) -геГегепсе (), ге/егепсей орега1ог= (Ьоо! х); //для Ь[!]=х: ге/е~ епсей орега1ог= (сопк1 ге~егепсей) //для Ь[!]=Ь[Д; Ьоо! орега1ог- () сопк1; //ннвертирует Ь[!] орега1ог Ьоо! () сопИ, //длях=Ь[!] ге/егепсей/!!р (); // для Ь[~].,й!р О; Шаблон Ы1яе1определен в пространстве имен я11(и представлен в <Ы1ке1>. Так уж исторически сложилось, что Ы1ке1 по стилю несколько отличается от классов стандартной библиотеки.
Например, если индекс (также называемый битовой позицией) выходит за пределы, генерируется исключение ои1 оу галие. Никакие итера- торы не обеспечиваются, Битовые позиции нумеруются справа налево — точно ты< же, как нумеруют разряды, так что значение Ь[(] — это рою (2, !). Таким образом, битовый набор можно представить себе как Х-разрядное двоичное число: позиция; 9875543210 Ъ(!ее!<10>(989): 17.5.3.1. Конструкторы Битовый набор множно сконструировать со значениями по умолчанию из битов в числе типа ипя!Опек( (опйс!п1и ли из строки я1г(П; 1етр!а1е<к!хе 1зу> с!акя Ыгяе1 ( рибйс: //- // конструкторы: Ыгке1 (),.
// !У- битный нул ь Ыгяе1 (ипк!упед !опд оа!); // биты из са! // )г — зто свойопво силзвола (у 20.2): 1етр!осе<с!авк СЬ, с!аяк Тг, с!аякА> //биты нз с<проки кбт ехр!!с11 Ьпяе1(сопкгЬакгс яЬЧпу<СЬ, Тг,А>й япв Ьоыс я1ппу<СЬ, Тг,А>звяке гуре рок = д, Ьакге кгг!пд<СЬ, Тг,А> яме 1уре и =Ьамс кгг!пд<СЬ, Тг А>зпрок(; Значение бита по умолчанию равно О. Когда залается аргумент типа ипк(плес! (опд 1п1, каждый бит в этом целом используется для инициализации соответствующего бита в битовом наборе (если такой есть).