|
Программирование >> Разработка устойчивых систем
copy(ns.begin(). ns.endO. ostreamJterator<Noisy>(cout. )); cout endl: cout \n--.........\n : map<1nt. Noisy> nm; fordnt i = 0: 1 < 10: i++) nm[i]: Пары создаются автоматически cout \n...........\n : for(size t j = 0: j < nm.sized: cout nm[ j ] = nm[j] endl: cout \n----......-\n : nm[10] = n: cout \n...........\n : nm.1nsert(make pair(47. n)): cout \n...........\n : cout \n nm.count(10)= nm.count(10) endl: cout nm.count(11)= nm.count(ll) endl: map<int. Noisy>::iterator it = nm.find(6): ifdt != nm.endO) cout value: (*it).second found in nm at location 6 endl: for(it = nm.beginO: it != nm.endO: it++) cout (*it).first : (*it).second . : cout \n-----......\n : } /:- При создании объекта ns типа set<Noisy> используются два итератора для массива объектов Noisy. Но у множеств также имеется конструктор по умолчанию и копирующий конструктор, причем конструктору можно передать объект, обеспечивающий альтернативную схему сравнения элементов. У множеств и отображений имеется функция insert(), предназначенная для занесения элементов в контейнер, а проверка принадлежности объекта к ассоциативному контейнеру может осуществляться двумя способами. Функция count() сообщает, сколько значений с заданным ключом присутствует в контейнере (для отображений и множеств она возвращает О или 1, но мультиотображения и мультимножества могут содержать несколько элементов с одинаковыми ключами). Функция find() возвращает итератор, установленный в позицию первого (а для отображений и множеств - единственного) вхождения заданного ключа. Если ключ отсутствует в контейнере, возвращается конечный итератор. Функции count() и find() поддерживаются всеми ассоциативными контейнерами, и это вполне логично. У ассоциативных контейнеров также имеются функции lower bound(), upper bound() и equaLrange(); как будет показано далее, они имеют смысл только для мультимножеств и мультиотобра-жений. Не пытайтесь изобрести какое-нибудь полезное применение этих функций для множеств и отображений - они предполагают существование интервалов одинаковых ключей, которые невозможны в этих контейнерах. Разработка оператора индексирования [ ] всегда связана с выбором. Поскольку этот оператор работает так же, как при индексировании массивов, программисты обычно не проверяют индекс перед использованием. Но что произойдет, если индекс выходит за границы? Для массива можно запустить исключение, но для отображений нарущение границ может означать, что вы хотите создать новый элемент с указанным ключом. Во всяком случае, контейнер тар библиотеки STL воспринимает происходящее именно так. Первый цикл for после создания объекта map<intNoisy> nm вроде бы ищет объекты оператором [ ], но на самом деле он создает новые объекты Noisy! При обращении к отсутствующему элементу отображения оператором [ ] контейнер автоматически создает новую пару ключ-значение (для значения используется конструктор по умолчанию). Следовательно, если вы хотите действительно проверить наличие элемента без его автоматического создания, следует задействовать функцию count() (простая проверка) или find() (получение итератора). Вывод значений контейнера с помощью оператора [ ] в цикле for порождает сразу несколько проблем. Прежде всего ключи должны иметь целочисленные значения (это условие выполняется в нащем примере). Вторая (и более серьезная проблема) состоит в том, что если ключи не образуют непрерывную последовательность, при переборе от нуля до размера контейнера будут автоматически созданы пары для отсутствующих ключей, а более высокие значения ключей окажутся упущенными. Наконец, если взглянуть на трассировку цикла for, вы увидите, что при выводе выполняется очень много операций. На первый взгляд соверщенно непонятно, почему простой перебор сопровождается таким количеством вызовов конструкторов и деструкторов. Ситуация проясняется только при просмотре кода операторной функции operator[ ] в шаблоне тар, который выглядит примерно так: mapped type& operator[] (const key type& к) { value type tmp(k,T()): return (*((insert(tmp)).first)).second: Функция map::insert() получает пару ключ-значение . Если в отображении уже имеется элемент с заданным ключом, ничего не происходит, иначе создается элемент. В любом случае функция возвращает новую пару из итератора вставленного элемента (то есть пары ключ-значение ) и логического флага (true, если элемент был вставлен в отображение). Стоит напомнить, что запись map::value type в действительности представляет собой простое определение типа для шаблона std:: pair: typedef pair<const Key. T> value type; Шаблон std::pairyжe встречался нам раньше. Как видно из определения, он предназначен для простого хранения значений двух независимых типов: template <class Tl. class Т2> struct pair { typedef Tl first type: typedef T2 second type: Tl first: T2 second: pairO: pair(const T1& X. const T2& y) : first(x). second(y) {} Параметризованный копирующий конструктор: tempiate<class U. class V> pair(const pair<U. V> &p): Шаблон pair очень удобен. Он особенно часто применяется, когда функция должна вернуть два объекта (команда return может получать только один объект). Для создания пар даже существует специальная сокращенная запись make pair(), использованная в программе AssociativeBasics.cpp. Итак, тип map::value type представляет собой пару ключ и значение (то есть один элемент отображения). Но компоненты pair хранятся по значению, то есть для занесения объектов в pair необходим вызов копирующего конструктора. Таким образом, создание объекта tmp в операторной функции map::operator[ ] потребует по крайней мере вызова копирующего конструктора и деструктора для каждого компонента pair. В нащем случае это терпимо, поскольку ключ является целым числом. Но если вы хотите увидеть, что может произойти при вызове операторной функции map::operator[ ], попробуйте запустить следующую программу: : C07:NoisyMap.cpp Отображение Noisy в Noisy {L} Noisy #include <map> #include Noisy.h using namespace std: int mainO { map<Noisy. Noisy> mnn; Noisy nl, n2: cout \n--------\n mnn[nl] = n2: cout \n........\n cout mnn[nl] endl: cout \n-.......\n } III- Пример показывает, что вставка и поиск порождают множество лищних объектов, и все это происходит из-за создания объекта tmp. Если вернуться к функции map::operator[ ], вы увидите, что вторая строка вызывает функцию insert() и передает ей объект tmp. Возвращаемое значение функции insert() представляет собой пару, в которой переменная first содержит итератор для вставленной пары ключ-значение , а переменная second - логический флаг, указывающий, была ли выполнена вставка. Оператор [ ] берет переменную first (итератор), разыменовывает ее для получения объекта pair и возвращает значение переменной second полученной пары (значение элемента). Итак, к достоинствам отображений следует отнести автоматическое создание несуществующих элементов, а к недостаткам - многочисленные лищние операции создания и уничтожения объектов при любом использовании операторной функции map::operator[ ]. Впрочем, пример AssociativeBasics.cpp также показывает, как избежать лищних затрат - достаточно обойтись без оператора [ ] там, где это возможно (функция insert() работает более эффективно). В множествах хранятся отдельные объекты, а в отображениях - пары ключ-значение , поэтому в аргументе insert() должен передаваться объект pair. Для его создания удобно воспользоваться функцией make pair(), как это сделано в нащем примере. При поиске объектов в отображении можно воспользоваться функцией count(), чтобы узнать о присутствии или отсутствии ключа, или функцией find() для получения итератора; разыменование этого итератора дает пару ключ-значение . Чтобы получить доступ к ее компонентам, выберите переменные first и second. Если запустить программу AssociativeBasics.cpp, вы увидите, что вариант с итератором
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |