оператор перегрузки <для std :: set меня смутил - PullRequest
0 голосов
/ 31 марта 2019

Я знаю, что мне нужно перегрузить оператор <для std :: set. </p>

Я перегружаю оператор <двумя классами: «UniqueID» и «UniqueIDWithBug». Единственное отличие состоит в том, что при сравнении «UniqueID» добавляется код <code>this->unique_id_a_ == t.unique_id_a_.

Затем я помещаю одинаковые элементы в два набора. Наконец я нахожу один элемент внутри наборов. Один комплект может найти его, другой - нет. Эта проблема долго смущала меня.

struct UniqueID {
    uint64_t unique_id_a_{0};
    uint64_t unique_id_b_{0};

    bool operator<(const UniqueID &t) const {
        if (this->unique_id_a_ < t.unique_id_a_) {
            return true;
        }
        if (this->unique_id_a_ == t.unique_id_a_ &&
            this->unique_id_b_ < t.unique_id_b_) {
            return true;
        }
        return false;
    }
};

struct UniqueIDWithBug {
    uint64_t unique_id_a_{0};
    uint64_t unique_id_b_{0};

    bool operator<(const UniqueIDWithBug &t) const {
        if (this->unique_id_a_ < t.unique_id_a_) {
            return true;
        }
        return (this->unique_id_b_ < t.unique_id_b_);
    }
};

// init data
std::set<UniqueID> _set = {
        {17303934402126834534u, 2922971136},
        {8520106912500150839u,  3118989312},
        {9527597377742531532u,  2171470080},
        {10912468396223017462u, 3972792320},
};
std::set<UniqueIDWithBug> _set_with_bug = {
        {17303934402126834534u, 2922971136},
        {8520106912500150839u,  3118989312},
        {9527597377742531532u,  2171470080},
        {10912468396223017462u, 3972792320}};

UniqueID _unique_id = {10912468396223017462u, 3972792320};
UniqueIDWithBug _unique_id_with_bug = {10912468396223017462u, 3972792320};

if (_set.find(_unique_id) == _set.end()) {
    std::cout << "_set not find" << std::endl;
}

if (_set_with_bug.find(_unique_id_with_bug) == _set_with_bug.end()) {
    std::cout << "_set_with_bug not find" << std::endl;
}

Выходы: _set_with_bug не найти

1 Ответ

5 голосов
/ 31 марта 2019

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

Ваш UniqueIDWithBug заказ не является.

Например, рассмотрим:

UniqueIDWithBug a{1, 10};
UniqueIDWithBug b{2, 5};

Теперь обратите внимание, что оба значения a < b и b < a истинны. Это всего лишь быстрая демонстрация того, что у вас нет строгого слабого порядка; действительно, это не заказ вообще!

Итак, ваша программа имеет неопределенное поведение. Внутренние элементы механизма std::set предполагают правильное упорядочение, а ваше - нет. В этом случае наблюдаемый результат был «элемент не найден». Это могло быть "сделать пиццу".

Создание хорошего строгого слабого порядка может быть трудным, но вы уже выполнили тяжелую работу, потому что UniqueID упорядочен правильно.

Кроме того, можно полностью отказаться от упорядочения, определить хеш-функцию и переключиться на unordered_set.

...