Шрифт:
Второй вариант реализации
ciStringCompare
основан на традиционном предикате STL; такая функция может использоваться в качестве функции сравнения в ассоциативных контейнерах. Реализация проста и предельно наглядна, поскольку достаточно модифицировать ciCharCompare
для получения функции сравнения символов с предикатным интерфейсом, а затем поручить всю работу по сравнению строк алгоритму lexicographical_compare
, занимающему второе место в STL по длине имени: bool ciCharLess(char c1, char c2) // Вернуть признак того,
{ // предшествует ли c1
// символу с2 без учета
return // регистра. В совете 46
tolower(static_cast<unsigned char>(c1))< // объясняется, почему
tolower(static_cast<unsigned char>(c2)); // вместо функции может
} // оказаться предпочтительным
// объект функции
bool ciStringCompare(const string& s1, const string& s2) {
return lexicographical_compare(s1.begin, s1.end, // Описание
s2.begin, s2.end, // алгоритма
ciCharLess); // приведено далее
}
Нет, я не буду долго хранить секрет. Самое длинное имя у алгоритма
set_symmetric_difference
. Если вы знаете, как работает
lexicographical_compare
, приведенный выше фрагмент понятен без объяснений, а если не знаете — это легко поправимо. Алгоритм
lexicographical_compare
является обобщенной версией strcmp
. Функция strcmp
работает только с символьными массивами, а lexicographical_compare
работает с интервалами значений любого типа. Кроме того, если strcmp
всегда сравнивает два символа и определяет отношение между ними (равенство, меньше, больше), то lexicographical_compare
может получать произвольный предикат, который определяет, удовлетворяют ли два значения пользовательскому критерию. В предыдущем примере алгоритм
lexicographical_compare
должен найти первую позицию, в которой s1
и s2
различаются по критерию ciCharLess
. Если для символов в этой позиции ciCharLess
возвращает true
, то же самое делает и lexicographical_compare
: если в первой позиции, где символы различаются, символ первой строки предшествует соответствующему символу второй строки, то первая строка предшествует второй. Алгоритм lexicographical_compare
, как и strcmp
, считает два интервала равных величин равными, поэтому для таких интервалов возвращается значение false
: первый интервал не предшествует второму. Кроме того, по аналогии с strcmp
, если первый интервал завершается до обнаружения различия, lexicographical_compare
возвращает true
— префикс предшествует любому интервалу, в который он входит. Довольно о
mismatch
и lexicographical_compare
. Хотя в этой книге большое значение уделяется переносимости программ, я просто обязан упомянуть о том, что функции сравнения строк без учета регистра символов присутствуют во многих нестандартных расширениях стандартной библиотеки C. Обычно эти функции называются stricmp
или strcmpi
и по аналогии с функциями, приведенными в данном совете, игнорируют проблемы интернационализации. Если вы готовы частично пожертвовать переносимостью программы, если строки заведомо не содержат внутренних нуль-символов, а проблемы интернационализации вас не волнуют, то простейший способ сравнения строк без учета регистра символов вообще не связан с STL. Обе строки преобразуются в указатели const char*
(см. совет 16), передаваемые при вызове stricmp
или strcmpi
: int ciStringCompare(const string& si1, const string& s2) {
return stricmp(sl.c_str, s2.c_str); // В вашей системе вместо stricmp
} // может использоваться другое имя
Функции
strcmp/strcmp
, оптимизированные для выполнения единственной задачи, обычно обрабатывают длинные строки значительно быстрее, чем обобщенные алгоритмы mismatch
и lexicographical_compare
. Если быстродействие особенно важно в вашей ситуации, переход от стандартных алгоритмов STL к нестандартным функциям C вполне оправдан. Иногда самый эффективный путь использования STL заключается в том, чтобы вовремя понять, что другие способы работают лучше. Совет 36. Правильно реализуйте copy_if
В STL имеется 11 алгоритмов, в именах которых присутствует слово
copy
: copy copy_backward
replace_copy reverse_copy
replace_copy_if unique_copy
remove_copy rotate_copy
remove_copy_if partial_sort_copy
uninitialized_copy
Но как ни странно, алгоритма
copy_if
среди них нет. Таким образом, вы можете вызывать replace_copy_if
и remove_copy_if
, к вашим услугам copy_backward
и reverse_copy
, но если вдруг потребуется просто скопировать элементы интервала, удовлетворяющие определенному предикату, вам придется действовать самостоятельно.