|
Программирование >> Включение нужных заголовков
работает с интервалами значений любого типа. Кроме того, если strcmp всегда сравнивает два символа и определяет отношение между ними (равенство, меньше, больше), то lexicographical compare может ползать произвольный предикат, который определяет, удовлетворяют ли два значения пользовательскому критерию. В предыдущем примере алгоритм lexicographical compare должен найти первую позицию, в которой si и s2 различаются по критерию ciCharLess. Если для символов в этой позиции CiCharLess возвращает true, то же самое делает и lexicographical compare: если в первой позиции, где символы различаются, символ первой строки предшествует соответствующему символу второй строки, то первая строка предшествует второй. Алгоритм lexicographicalcompare, как и strcmp, считает два интервала разных величин равными, поэтому для таких интервалов возвращается значение fal se: первый интервал не предшествует второму. Кроме того, по аналогии с strcmp, если первый интервал завершается до обнаружения различия, lexicographical compare возвращает true - префикс предшествует любому интервалу, в который он входит. Довольно о mismatch и lexicographical compare. Хотя в этой книге большое значение уделяется переносимости программ, я просто обязан упомянуть о том, что функции сравнения строк без зета регистра символов присутствуют во многих нестандартных расширениях стандартной библиотеки С. Обычно эти функции называются stricmp или strcmpi и по аналогии с функциями, приведенными в данном совете, игнорируют проблемы интернационализации. Если вы готовы частично пожертвовать переносимостью программы, если строки заведомо не содержат внутренних нуль-символов, а проблемы интернационализации вас не волнуют, то простейший способ сравнения строк без зета регистра символов вообще не связан с STL. Обе строки преобразуются в указатели const char* (см. совет 16), передаваемые при вызове stricmp или strcmpi: int CiStringCompareCconst strings si, const strings s2) { return stricnip(sl.c str().s2.c str()); В вашей системе вместо stricmp } может использоваться другое имя Функции strcmpi/stricmp, оптимизированные для выполнения единственной задачи, обычно обрабатывают длинные строки значительно быстрее, чем обобщенные алгоритмы mismatch и lexicographical compare. Если быстродействие особенно важно в вашей ситуации, переход от стандартных алгоритмов STL к нестандартным функциям С вполне оправдан. Иногда самый эффективный пзггь использования STL заключается в том, чтобы вовремя понять, что другие способы работают лзше. Совет 36. Правильно реализуйте copyjf в STL имеется 11 алгоритмов, в именах которых присутствует слово сору: сору copbackward replacecopy reverse copy replace copy if unique copy reniove copy rotate copy reniove copy i f parti al sort copy uninitiali2ed copy Но как ни странно, алгоритма copy i f среди них нет. Таким образом, вы можете вызывать гер1 ace copy i f и remove copy i f, к вашим услугам copy backward и reverse copy, но если вдруг потребуется просто скопировать элементы интервала, удовлетворяющие определенному предикату, вам придется действовать самостоятельно. Предположим, имеется функция для отбора дефектных объектов Widget: bool isDefectiveCconst WidgetS w): Требуется скопировать все дефектные объекты Widget из вектора в сегг. Если бы алгоритм copy i f существовал, это можно было бы сделать так: vector<Wi dget> wi dgets; copy if(widgets.begin().windgets.end(), He компилируется - ostreamJterator<Widget>(cerr. \n ). в STL не существует isDefective); алгоритма copyjf По иронии судьбы алгоритм copy i f входил в исходную версию STL от Hewlett Packard, которая была заложена в основу библиотеки STL, ставшей частью стандартной библиотеки C-I-I-. В процессе сокращения HP STL до размеров, подходящих для стандартизации, алгоритм copy i f остался за бортом. В книге The С++ Programming Language [7] Страуструп замечает, что реализация copy i f выглядит элементарно - и он прав, но это вовсе не означает, что каждый программист сразу придет к нужному решению. Например, ниже приведена вполне разумная версия copy i f, которую предлагали многие программисты (в том числе и я): tempiate<typename Inputlterator, Не совсем правильная typename Outputlterator, реализация copyjf typename Predicate> Outputlterator copyjf (Inputlterator begin. Inputlterator end, Outputlterator destBegin. Predicate p) return renrave copy i f(begin,end.destBegin,notl(p)): Решение основано на простом факте: хотя STL не позволяет сказать скопировать все элементы, для которых предикат равен true , но зато можно потребовать скопировать все элементы, кроме тех, для которых предикат неравен true . Создается впечатление, что для реализации copy i f достаточно поставить notl перед предикатом, который должен передаваться copy if, после чего передать полученный предикат renrove copy i f. Результатом является приведенный выше код. Если бы эти рассуждения были верны, копирование дефектных объектов Wi dget можно было бы произвести следующим образом: copyjf (widgets, begi nO.windgets.endO, Хорошо задумано, ostreamJterator<Widget>(cerr. \n ), но не компилируется isDefective); Компилятор недоволен попыткой применения notl к isDefective (это происходит внутри copy if). Как объясняется в совете 41, notl не может напрямую приме- няться к указателю на функцию - сначала указатель должен пройти через ptr f un. Чтобы вызвать эту реализацию copy i f, необходимо передать не просто объект функции, а адаптируемый объект функции. Сделать это несложно, однако возлагать эти хлопоты на будущих клиентов алгоритма STL нельзя. Стандартные алгоритмы STL никогда не требуют, чтобы их функторы были адаптируемыми, поэтому нельзя предъявлять это требование к copyi f. Приведенная выше реализация хороша, но недостаточно хороша. Правильная реализация copy i f должна выглядеть так: tempiate<typename Inputlterator, Правильная typename Output Iterator, реализация copy if typename Predicate> Outputlterator copyjf (Inputlterator begin, Inputlterator end, Outputlterator destBegin, Predicate p) while begin!=end) { if(p(*begin)) *destBegin++ = *begin; ++begin; return destBegin; Поскольку алгоритм copy J f чрезвычайно полезен, a неопытные программисты STL часто полагают, что он входит в библиотеку, можно порекомендовать разместить реализацию copyif - правильную реализацию! - в локальной вспомогательной библиотеке и использовать ее в случае надобности. Совет 37. Используйте accumulate или for each для обобщения интервальных данных Иногда возникает необходимость свести целый интервал к одному числу или, в более общем случае, к одному объекту. Для стандартных задач обобщения существуют специальные алгоритмы. Так, алгоритм count возвращает количество элементов в интервале, а алгоритм count i f возвращает количество элементов, соответствующих заданному предикату. Минимальное и максимальное значение элемента в интервале можно получить при помощи алгоритмов mi п е1 ement и max el ement. Но в некоторых ситуациях возникает необходимость обработки интервальных данных по нестандартным критериям, и в таких случаях нужны более гибкие и универсальные средства, нежели алгоритмы count, count if, mi n el ement и max el ement. Предположим, вы хотите вычислить сумму длин строк в контейнере, произведение чисел из заданного интервала, усредненные координаты точек и т. д. В каждом из этих случаев производится обобщние интервала, но при этом критерий обобщения вы должны определять самостоятельно. Для подобных ситуаций в STL предусмотрен специальный алгоритм accumul ate. Многим программистам этот алгоритм незнаком, поскольку в отличие от большинства алгоритмов он не находится в <algorithm>, а вместе с тремя другими числовыми алгоритмами (inner product, adjacent difference и partial sum) выделен в библиотеку <numeric>.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |