Оценка равенства в ассоциативных контейнерах (STL)

Я знаю, что ассоциативные контейнеры STL (и другие сортируемые контейнеры, я бы предположил) используют критерий сортировки для проверки на равенство.

критерий сортировки для контейнеров по умолчанию равен st:: less, чтобы сделать тест равенства для контейнера:

if (! (lhs < rhs || rhs < lhs))

или что-то подобное. У меня есть пара вопросов по этому поводу...

прежде всего, это кажется странно неэффективным способом сравнения для равенства-почему STL делает это так это? Я бы ожидал, что контейнеры STL просто возьмут дополнительный параметр по умолчанию для равенства.

мой второй вопрос больше касается оценки оператора if выше в целом. В C++ какая часть этого утверждения будет оценена (lhs > rhs), была истинной? Прекратит ли он пытаться после оценки стороны, которая потерпела неудачу, тем самым экономя некоторую эффективность? Если да, то какая часть выражения оценивается первой?

5 ответов


в "эффективном STL" Скотт Мейерс имеет обширную дискуссию об этом в пункт 19:

поймите разницу между равенством и эквивалентностью.

равенство, как и следовало ожидать, основана на operator==.

эквивалентности " основан на относительном упорядочении значений объектов в отсортированном диапазоне... Два объекта имеют значения eqivalent в контейнер c Если не предшествует другому в c порядок сортировки."

Мейерс выражает это так:

!( w1 < w2 ) // it's not true that w1 < w2
&&           // and
!( w2 < w1 ) // it's not true that w2 < w1

Мейерс затем повторяет:

это имеет смысл: два значения эквивалентны (по отношению к некоторым критерий упорядочения), если ни один из них не предшествует другому (в соответствии с этим критерий.)

что касается того, почему STL делает это таким образом:

С помощью только одной функции сравнения и с использованием эквивалентность как арбитр, что значит быть "тем же" стандартные ассоциативные контейнеры... избегайте путаницы, которая возникает от смешения использования равенства и эквивалентности в стандартные ассоциативные контейнеры.

прочитайте пункт 19 (который охватывает большую часть 6 страниц) для себя, чтобы получить полный аромат.


ассоциативные контейнеры STL

вы имеете в виду: стандартные сортированные ассоциативные контейнеры C++.

Я ожидал, что контейнеры STL просто возьмут дополнительный параметр по умолчанию для равенства.

и что бы это дало? В вашем учебнике алгоритм красно-черного дерева вместо

if (x < y)
    // ...
else if (y < x)
    // ...
else
    // equality

ты

if (x == y)
    // equality
else if (x < y)
    // ...
else
    // y < x

так еще два сравнения в худшем случае.

ответ к комментариям к этому ответу: наличие только оператора less-than для поставки значительно упрощает использование контейнеров, поскольку нет необходимости поддерживать согласованность между less-than и equals. Давайте представим, что у вас есть программа, хранящая числа с плавающей запятой. Однажды кто-то решает заменить побитовое равенство float_equals функция, которая только что была использована некоторым контейнером но и по их коду, по приблизительному сравнению. Если этот человек не обновит , потому что их код не использует эту функцию, затем ваш код контейнера таинственным образом ломается.

(Oh и в показанном примере кода, короткое замыкание применяется, как всегда.)


Что касается второго вопроса: применяются стандартные правила ленивой оценки C для булевых выражений. Если LHS || верно, RHS не оценивается.


в C++ оценивает, если() слева направо для вашего случая с ||. Оценивает левую сторону (LHS


прежде всего, это кажется странно неэффективным способом сравнения для равенства

да, но сортированные контейнеры делают этот тест относительно редко.

использование функции сравнения, такой как strcmp будет лучше. Использование обоих меньше-чем и сравнить было бы еще лучше.

в C++, какая часть этого утверждения будет оценена (lhs > rhs) была истинной?

в C и в C++, a && b, a || b, a, b, a ? b : c оцениваются слева направо, причем оценивается только полезная правая часть (за исключением перегружен &&, ||, , операторы в C++).

это позволяет несколько полезных коротких тестов, таких как:p != NULL && *p > 2