|
Программирование >> Оптимизация возвращаемого значения
while (begin != end && *begin != value) ++begin; return begin; Обратите внимание: при преобразовании в шаблон вместо передачи value по значению выполняется передача по ссылке на const. Это связано с тем, что теперь передаются произвольные типы, и поэтому приходится учитывать затраты на передачу по значению. Для каждого передаваемого по значению параметра приходится вызывать его конструктор и деструктор при всяком вызове функции. Чтобы избежать этих затрат, надо использовать передачу по ссылке, исключая создание и удаление объекта. Этот шаблон достаточно хорош, но его можно еще ул5шить. Посмотрите на операции с begin и end. Из них используются только сравнение на равенство и неравенство, разыменование, префиксный инкремент (см. правило 6) и копирование (для возвращаемого значения функции - см. правило 19). Все эти операции можно перегрузить, поэтому зачем ограничивать функцию find работой с указателями? Почему не разрешить использование не только указателей, но и любых других объектов, поддерживающих эти операции? В результате вы освободите функцию find от встроенного значения операций с указателями. Например, можно будет определить похожий на указатель объект для связного списка, префиксный оператор инкремента которого перемещал бы вас на следующий элемент в списке. Эта концепция и лежит в основе итераторов STL. Итераторы - это, как уже говорилось, похожие на указатели объекты, предназначенные для использования с контейнерами STL. Они близкие родственники интеллектуальных указателей, описанных в правиле 28, но последние обычно более амбициозны . С технической точки зрения и те, и другие реализуются при помощи одинаковых методов. Рассматривая итераторы как похожие на указатели объекты, можно заменить в функции find указатели на итераторы, переписав функцию find: template<class Iterator, class Т> Iterator find(Iterator begin, Iterator end, const T& value) { while (begin != end && *begin != value) ++begin; return begin; Поздравляю! Вы только что написали часть стандартной библиотеки шаблонов. Она содержит десятки алгоритмов, работающих с контейнерами и итераторами, и функция find является одним из них. Контейнеры в STL имеют типы bitset, vector, list, deque, queue, priority queue, stack, set и map, и вы можете применять функцию find к любому из этих типов: list<char> charList; Создать объект STL для списка символов. Найти положение первого символа х в charList. list<char>::iterator it = find(charList.begin{), charList.endO , X ) ; Постойте! , - кричите вы, - Это совсем не похоже на предыдущие примеры массивов! . Нет, они похожи; вы просто должны знать, в чем искать это сходство. Для вызова функции find для объекта list вам нужны итераторы, указывающие на первый элемент списка и на элементрасположенный сразу же за концом списка. Без помощи со стороны класса list это было бы нелегкой задачей, так как реализация list не известна. К счастью, класс list (как и все контейнеры STL) должен содержать функции-члены begin и end. Эти функции-члены возвращают нужные вам итераторы, которые и передаются в качестве двух первых параметров функции find в примере. Завершив свое выполнение, функция find возвращает объект-итератор, указывающий на найденный элемент (если он существует) или на charList. end () (если искомого элемента нет в списке). Поскольку вы ничего не знаете о реализации класса list, то вы ничего не знаете и о реализации итераторов в list. Как тогда вы сможете выяснить тип объекта, возвращаемого функцией find? И снова вам на помощь приходит класс list, который, как и все контейнеры STL, содержит определение типа iterator, соответствующее типу итераторов в 1 i s t. Так как объект charList является списком символов, то итераторы для такого списка имеют тип list<char>::iterator, и именно этот тип используется в вышеприведенном примере. (На самом деле в каждом классе-контейнере STL определяются два типа итераторов, iterator и const iterator. Первый из них выступает в качестве обычного указателя, а последний - в качестве указателя на const.) Такой же подход может использоваться и для других контейнеров STL. Кроме того, указатели С++ также являются итераторами STL, поэтому исходные примеры работы с массивами будут работать с функцией find из STL: int values[50] ; int *firstFive = find(values, Нормально, values+50, вызывает функцию 5) ; find из STL. Принцип организации стандартной библиотеки шаблонов очень прост. Она представляет собой набор шаблонов классов и функций, придерживающихся ряда соглашений. Набор классов STL содержит функции, такие как begin и end, которые возвращают объекты-итераторы определенных в классе типов. Функции алгоритмов STL перемещаются между наборами объектов, используя объекты итераторы для наборов STL. Итераторы STL работают как указатели. Вот в сущности, и все. Нет большой иерархии наследования, нет виртуальных функций и того подобного. Просто несколько шаблонов классов и функций и набор соглашений, которых они придерживаются. Это приводит к новому откровению: стандартная библиотека шаблонов является расширяемой. Вы можете добавлять к семейству STL свои наборы, алгоритмы и итераторы. До тех пор пока вы следуете соглашениям STL, стандартные наборы STL будут работать с вашими алгоритмами, а ваши наборы со стандартными алгоритмами STL. Конечно, ваши шаблоны не станут частью стандартной библиотеки C-I-I-, но они будут построены на тех же принципах, что позволит использовать их повторно. Библиотека C-i-i- содержит намного больше возможностей, чем описано в этой книге. Поэтому чтобы эффективно использовать ее, обратитесь к другим источникам информации (их список приведен в приложении 1), где вы найдете подробные сведения как о библиoтeкe,taк и о соглашениях STL. Стандартная библиотека С++ намного богаче библиотеки С, и время, которое вы потратите на ознакомление с ней, будет потрачено не напрасно. Кроме того, воплощенные в библиотеке принципы разработки - универсальность, расширяемость, эффективность, возможность настройки и повторного использования - сами по себе стоят вашего внимания. Из5ая стандартную библиотеку С++, вы не только пополните ваши знания о готовых компонентах, которые сможете использовать в своих программах, но и поймете, как более эффективно применять С++ и разрабатывать собственные библиотеки.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |