Удаление члена `std :: set` путем указания значения указанного члена - PullRequest
2 голосов
/ 24 сентября 2019

У меня есть следующий код C ++.Я пытаюсь стереть член набора, явно указав его значение, и почему-то это не работает.

#include <iostream>
#include <set>

struct compareWeights
{
    template<typename T>
    bool operator()(const T& l, const T& r) const
    {

        return l.second <= r.second;
    }
};


int main(){


        std::set<std::pair<std::string, int>, compareWeights> set = {
        {"A", 4}, {"B", 4}, {"C", 1}, {"A", 0}, {"B", 3}
        };

        for (auto const &p: set) {
            std::cout << p.first << " " << p.second << '\n';
        }

        set.erase({"A", 0});  //Problem area

        std::cout << "\n";

        //Just to print the contents of the new set after erasing
        for (auto const &p: set) {
            std::cout << p.first << " " << p.second << '\n';
        }


    return 0;

}

Я прокомментировал, чтобы выделить место, где происходит проблема.Я вижу, что std::set.erase возвращает 0 (не находит элемент), но я не уверен, почему метод erase не может найти элемент.

Я попытался изменить erase на

set.erase(std::make_pair("A", 0))

Но все равно ничего не изменилось.

Ответы [ 3 ]

4 голосов
/ 24 сентября 2019

Ваш компаратор не может обеспечить строгий слабый порядок , и поэтому его использование в std::set вызывает неопределенное поведение.Предположим, вы изменили его на:

return l.second < r.second;

Этот фиксированный компаратор был бы строгим слабым порядком, и {"A", 0} должен быть найден без проблем.Тем не менее, это также может иметь другую проблему: набор будет рассматривать два объекта с одинаковым значением second как эквивалентные, даже если они имеют разные значения first.Вы не сможете вставить как {"A", 4}, так и {"B", 4}.Кроме того, поиск {"B", 0} найдет {"A", 0}, поскольку набор не может различить два.Чтобы решить эти проблемы, вы можете написать:

return l.second < r.second || (l.second == r.second && l.first < r.first);
3 голосов
/ 24 сентября 2019

Проблема, скорее всего, связана с функцией сравнения.Измените <= на <.

template<typename T>
bool operator()(const T& l, const T& r) const
{
    // return l.second <= r.second;
    return l.second < r.second;
}

Если вам нужно сначала заказать second пары, а затем выполнить first пары, используйте:

template<typename T>
bool operator()(const T& l, const T& r) const
{
    if ( l.second != r.second )
    {
       return l.second < r.second;
    }
    return l.first < r.first;
}

Если вы хотите упорядочить first пары, а затем second пары, используйте:

template<typename T>
bool operator()(const T& l, const T& r) const
{
    if ( l.first != r.first )
    {
       return l.first < r.first;
    }
    return l.second < r.second;
}

Читайте строго слабый порядок дляпонять, почему это проблема.

1 голос
/ 24 сентября 2019

Компаратор должен проверить, если l < r и два элемента считаются эквивалентными точно, если !(l < r) && !(r < l).Однако, с вашим компаратором, если два элемента равны, то оба значения l < r и r < l оцениваются как true.В более формальных терминах: компаратор должен реализовать строгий слабый порядок.

Чтобы исправить это, вам просто нужно заменить

return l.second <= r.second;

на

return l.second < r.second;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...