бага в операторе == std::set
От: Caracrist https://1pwd.org/
Дата: 28.07.13 06:52
Оценка:
В студийной имплементации оператора сравнения игнорируется traits с которыми он объявлен. Там тупо используется оператор == на каждый из элементов.
Что об этом говорит стандарт?
~~~~~
~lol~~
~~~ Single Password Solution
Re: бага в операторе == std::set
От: Evgeny.Panasyuk Россия  
Дата: 28.07.13 07:40
Оценка: +1
Здравствуйте, Caracrist, Вы писали:

C>В студийной имплементации оператора сравнения игнорируется traits с которыми он объявлен.


Что за traits?
Тот который ::key_compare, который strict weak ordering, который не обязательно total ordering и у которого эквивалентность не обязательно означает равенство?

C>Там тупо используется оператор == на каждый из элементов.


template<typename Container>
void test_equality(Container &x, Container &y)
{
    bool equal1 = (x == y);
    bool equal2 =
    (
        distance(begin(x), end(x)) == distance(begin(y), end(y)) &&
        equal(begin(x), end(x), begin(y))
    );
    assert( equal1 == equal2 ); // ?
}

Ты хочешь чтобы assertion когда-нибудь фэйлилось?

C>Что об этом говорит стандарт?


Стандарт говорит что название топика — BS.
Re: бага в операторе == std::set
От: uzhas Ниоткуда  
Дата: 28.07.13 07:56
Оценка: 6 (1)
Здравствуйте, Caracrist, Вы писали:

C>В студийной имплементации оператора сравнения игнорируется traits с которыми он объявлен. Там тупо используется оператор == на каждый из элементов.

C>Что об этом говорит стандарт?
вот что говорит cppreference
http://www.cplusplus.com/reference/set/set/operators/

Operations == and != are performed by first comparing sizes, and if they match, the elements are compared sequentially using algorithm equal, which stops at the first mismatch.

Operations <, >, <= and >= behave as if using algorithm lexicographical_compare, which compares the elements sequentially using operator< reflexively, stopping at the first mismatch.

Notice that none of these operations take into consideration the internal comparison object of neither container.


http://www.cplusplus.com/reference/algorithm/equal/

The elements are compared using operator== (or pred, in version (2)).

Re[2]: бага в операторе == std::set
От: Кодт Россия  
Дата: 28.07.13 11:16
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Caracrist, Вы писали:


C>>В студийной имплементации оператора сравнения игнорируется traits с которыми он объявлен. Там тупо используется оператор == на каждый из элементов.

C>>Что об этом говорит стандарт?
U>вот что говорит cppreference
U>http://www.cplusplus.com/reference/set/set/operators/

Это ты процитировал cplusplus, а не cppreference.

http://en.cppreference.com/w/cpp/container/set/operator_cmp

1-2) Checks if the contents of lhs and rhs are equal, that is, whether lhs.size() == rhs.size() and each element in lhs has equivalent element in rhs at the same position.
3-6) Compares the contents of lhs and rhs lexicographically. The comparison is performed by a function equivalent to std::lexicographical_compare.

1-2 — это == и !=, 3-6 — операторы неравенств.

Вообще, cplusplus.com уже ловили на неточностях, но я не ожидал от более доверительного cppreference.com увидеть такое расплывчатое описание.


Опыты над gcc 4.7.3 показывают: std::set в любом случае забивает на свой параметр-компаратор, и использует операторы над типом аргумента — как для равенств, так и для неравенств.
Хотя и std::equals, и std::lexicographical_compare можно параметризовать.

Вот такая неувязочка.
Не, понятно, что операторы над множеством должны быть непротиворечивы — и использовать либо только один способ (параметр-компаратор), либо другой (операторы над аргументом).
Но почему именно тот, а не другой
Перекуём баги на фичи!
Re[3]: бага в операторе == std::set
От: Evgeny.Panasyuk Россия  
Дата: 28.07.13 16:08
Оценка: 66 (1)
Здравствуйте, Кодт, Вы писали:

C>>>Что об этом говорит стандарт?

U>>вот что говорит cppreference
U>>http://www.cplusplus.com/reference/set/set/operators/
К>Это ты процитировал cplusplus, а не cppreference.
К>http://en.cppreference.com/w/cpp/container/set/operator_cmp

см "Table 96 — Container requirements" и "Table 98 — Optional container operations"

К>Хотя и std::equals, и std::lexicographical_compare можно параметризовать.


std::set параметризуется strict weak ordering, а не total ordering. Это означает, что из !cmp(x, y) && !cmp(y, x) не следует x == y.

К>Вот такая неувязочка.

К>Не, понятно, что операторы над множеством должны быть непротиворечивы — и использовать либо только один способ (параметр-компаратор), либо другой (операторы над аргументом).
К>Но почему именно тот, а не другой

std::set это container, "Table 96" определяет "Container requirements", где "a == b" делает то, что я показал выше.
Если бы operator== делал что-нибудь другое для set'а — тогда либо set не был бы стандартным контейнером, либо стандартный контейнер был бы без operator==, либо operator== имел бы какую-нибудь странную семантику.

Вот какое определение давал Степанов для равенства:

x == y ⇒ ∀ “reasonable” function foo, foo(x)==foo(y)

В моём понимании, вот такая функция:
template<typename Container>
auto first(const Container &x)
{
    assert( !x.empty() );
    return *x.begin();
}

является “reasonable”, для которой должно выполнятся first(x) == first(y), при x == y.

P.S. недавно подобная тема была в списке рассылки Boost.
Re[3]: бага в операторе == std::set
От: jazzer Россия Skype: enerjazzer
Дата: 29.07.13 05:16
Оценка: 33 (1)
Здравствуйте, Кодт, Вы писали:

К>Вот такая неувязочка.

К>Не, понятно, что операторы над множеством должны быть непротиворечивы — и использовать либо только один способ (параметр-компаратор), либо другой (операторы над аргументом).
К>Но почему именно тот, а не другой

Ну вот представь, что ты загружаешь откуда-нть толпу человек (ученики-дежурные на сегодня) и организуешь их в сет по классу (потому что один дежурный от каждого класса).
А потом загружаешь то же самое за вчера.
И сравниваешь.
Вот что бы ты ожидал от сегодня==вчера? Имхо, они должны считаться равными только если список дежурных не изменился со вчерашнего дня. Во всех остальных случаях (разные ученики, или от какого-то класса не прибыло дежурного вообще) они должны считаться неравными.

Иными словами, при всех сравнениях стандартных контейнеров сравниваются сами элементы, и способ хранения/упорядочения их внутри контейнера не должен никакого влияния на это сравнение оказывать.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: бага в операторе == std::set
От: omgOnoz  
Дата: 30.07.13 13:05
Оценка: -1
Да они укурились со своими стандартами. Всегда знал, что 2 сета должны быть равны, если содержат одинаковый набор элементов. А тут
Re[3]: бага в операторе == std::set
От: Evgeny.Panasyuk Россия  
Дата: 30.07.13 13:56
Оценка:
Здравствуйте, omgOnoz, Вы писали:

O>Да они укурились со своими стандартами. Всегда знал, что 2 сета должны быть равны, если содержат одинаковый набор элементов. А тут


а тут 2 сета равны, "если содержат одинаковый набор элементов"
Re[4]: бага в операторе == std::set
От: omgOnoz  
Дата: 30.07.13 14:49
Оценка:
EP>а тут 2 сета равны, "если содержат одинаковый набор элементов"
Ну в общем да, нельзя сравнивать сеты с разными компараторами... на уровне компиляции зашибет
Re[5]: бага в операторе == std::set
От: Evgeny.Panasyuk Россия  
Дата: 30.07.13 14:52
Оценка:
Здравствуйте, omgOnoz, Вы писали:

EP>>а тут 2 сета равны, "если содержат одинаковый набор элементов"

O>(18:12) Если содержимое сетов по разному отсортировано?
O>(18:26) Одинаковый набор элементов может быть по разному отсортирован
O>(18:38) Даже если элементы set-а по разному отсортированы?
O>(18:49)Ну в общем да, нельзя сравнивать сеты с разными компараторами... на уровне компиляции зашибет

А ты чего так нервничаешь?
Если у set'овских strict weak ordering разные типы — то == даже не скомпилируется (написал до того как ты удалил очередное своё сообщение).
А платить O(N*ln(N)) за то что в 99% случаев стоит O(N) — из-за того что кто-то хочет чесать правое ухо левой пяткой, я не согласен
Re[6]: бага в операторе == std::set
От: omgOnoz  
Дата: 30.07.13 21:53
Оценка: -1 :)
Компаратор всегда можно написать свой, хоть за О(1). А то как оно сделано — это неприятные ограничения.
И разность типов еще определяться типом компараторов и даже аллокаторов...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.