使用std :: set.erase后,std :: set包含重复元素

时间:2014-11-19 21:00:21

标签: c++ c++11 set

嗯,我需要设定一个玩家计时器,每个玩家每30分钟执行一次。

而不是循环播放所有玩家std::set<std::pair<playerid,last_time_executed>>(两者都是整数std::set<std::pair<int,int>>)和:

  • 我知道如何按时间值排序,
  • 我知道如何插入一个元素而不插入重复的playerid(一组中的一个playerid)

但我不知道如何仅通过playerid擦除一个元素,所以我用我的大脑选择的随机值进行了一些测试,结果如下:

#include <iostream>
#include <set>

typedef std::pair<int, int> Pair;
struct Cmp{bool operator ()(const Pair &a, const Pair &b){return a.second < b.second;}};
std::set<Pair, Cmp> myset;

int main() {

    myset.insert(Pair(0, 5));
    myset.insert(Pair(1, 0));
    myset.insert(Pair(1, 1));
    myset.erase(Pair(0, 698));

    std::cout << myset.size() << std::endl;
    for (auto i : myset)
        std::cout << "(" << i.first << "," << i.second << ")" << std::endl;
    return 0;
}

这实际上打印....(注意重复的id'1')

3 (1,0) (1,1) (0,5)

虽然这个:

int main() {

    myset.insert(Pair(0, 5));
    myset.insert(Pair(1, 0));
    myset.insert(Pair(1, 1));

    std::cout << myset.size() << std::endl;
    for (auto i : myset)
        std::cout << "(" << i.first << "," << i.second << ")" << std::endl;
    return 0;
}

打印出来(没有重复的ID?):

2 (1,1) (0,5)

现在更加严厉(!),这个:

int main() {

    myset.insert(Pair(0, 5));
    myset.insert(Pair(1, 0));
    myset.insert(Pair(1, 1));
    myset.erase(Pair(0, 0));
    std::cout << myset.size() << std::endl;
    for (auto i : myset)
        std::cout << "(" << i.first << "," << i.second << ")" << std::endl;
    return 0;
}

打印出来(没有重复的ID?):

2 (1,1) (0,5)

这真是令人惊讶,因为我期望与第一次测试中的输出相同。

为什么会这样?

2 个答案:

答案 0 :(得分:0)

您的比较谓词仅比较 该对的second字段。

&#34;碰撞&#34;在第一个领域是无关紧要的。

更改它以获得您描述的行为:

struct Cmp {
    bool operator()(const Pair &a, const Pair &b) { return a.first < b.first; }
};

<强> Live On Coliru

另外,正如其他人所注意到的,这更像是std::map<idtype, valuetype>

<强> Live On Coliru

#include <iostream>
#include <map>

std::map<int, int> myset;

int main() {

    mymap.emplace(0, 5);
    mymap.emplace(1, 0);
    mymap.emplace(1, 1);
    mymap.erase(0);

    std::cout << myset.size() << std::endl;
    for (auto i : myset)
        std::cout << "(" << i.first << "," << i.second << ")" << std::endl;
    return 0;
}

注意,要实际更新(现有)密钥的值:

    mymap[0] = 5;
    mymap[1] = 0;
    mymap[1] = 1;

答案 1 :(得分:0)

std::set使用比较器"determine both the order the elements follow in the container and whether two element keys are equivalent"

由于您的比较器仅比较last_time_executed,因此如果它们具有相同的Pair,它会认为两个last_time_executed等效。因此,当您执行myset.erase(Pair(0, 0));时,它会删除Pair(1, 0)

当我运行你的第二个例子时,我得到了我期望的重复玩家ID。