std :: set未检测到重复的自定义对象 [英] std::set doesn't detect duplicate custom objects

查看:84
本文介绍了std :: set未检测到重复的自定义对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一张地图,用于保留球队名称和球队std:pair<std::string, std::vector<std::string> >球员,以及一组指向球员的指针,以使球员按获胜顺序降序排列.而且有一个陷阱-一名球员可以参加多个团队.

I have a map for keeping the team name and players of the team std:pair<std::string, std::vector<std::string> > and a set of pointers to players to keep the players sorted in descending order by wins. And there's the catch - one player can participate in more than one team.

    class Player
{
public:
    int wins;
    std::string name;

    Player() {}
    Player(std::string name) : wins(0), name(name) {}

    bool operator<(const Player* rhs) const
    {
        return this->wins > rhs->wins;
    }

    bool operator()(const Player* lhs, const Player* rhs) const
    {
        return lhs->wins > rhs->wins;
    }
};

int main()
{
    // EXAMPLE
    std::set<Player*> players;
    std::map<std::string, std::vector<Player> > teams;

    teams["TeamA"].push_back(Player("a"));
    teams["TeamB"].push_back(Player("a"));;
    players.insert(&teams["TeamA"].front());
    players.insert(&teams["TeamB"].front());

    std::cout << players.size(); // output 2 

    return 0;
}

如您所见,"TeamA"和"TeamB"中的玩家是相同的,但仍在集合中添加了两个指针,我不知道为什么...我缺少什么吗?

As you can see the players in 'TeamA' and 'TeamB' are identical but still in the set are added two pointers and I can't figure it out why.. Is there something I am missing ?

推荐答案

如果我的假设是正确的,那么这将不会如您所愿!

If my assumptions are correct, this won't work out as you expect!

teams["TeamA"].push_back(Player("a"));
teams["TeamB"].push_back(Player("a"));

我在这里假设您希望一个叫"a"的球员成为两支球队的一部分.如果该玩家在A队中获胜,则其获胜属性会增加,就如同在B队中获胜一样.

I assume here that you want one single player called "a" to be part of two teams. If this player wins within team A, its wins property is incremented, just the same as if it won within team B.

但是,您实际上要做的是创建两个不同的玩家,都被称为"a",并且他们都出现在组合中(嗯,实际上不是,请参阅下文...),每个人都保持自己的胜利(第一个玩家"a"在A队中获胜,第二名在B队中获胜.

What you actually did, though, is creating two different players, both called "a", and they both appear in the set (well, actually not, see below...), each one maintaining its own wins (first player "a" the wins in team A, second one the wins in team B).

将要做的是在玩家组中创建玩家,并将这些单个实例添加到各个团队的向量中:

What you would have to do is creating the players in the players' set and add these single instances to the vectors of the various teams:

std::set<Player> players;
std::map<std::string, std::vector<Player*> > teams;
auto entry = players.insert(Player("a"));
teams["TeamA"].push_back(&entry->first);

但这也不可行:您的比较仅基于获胜!如果您输入两个不同的玩家(顺便说一句,如果应用StoryTeller的修复程序,也会发生同样的事情!),两者都以0获胜开始.因此,两个玩家的比较将相等(a < bb < a因此适用平等),因此只有一名球员会参加比赛.

But this won't work out either: Your comparison is based on the wins only! If you enter two different players (the same will happen, by the way, if you apply StoryTeller's fix!), both start with a win of 0. So both players will compare equal (a < b and b < a both won't apply thus equality), so only one single player will enter the set...

此外,std::set没有自动更新"功能!它要求其条目保持不变(至少将其成员用于比较!).因此,如果您在比赛进行时更新自己的获胜信息,则您的集合中的排序将完全丢失(除此之外,修改地图或集合的键实际上是未定义的行为).

Additionally, std::set has no "auto-update" feature! It requires that its entries remain constant (at least the members of which are used for the comparison!). So if you update your wins on the run of your competitions, the sorting in your set will get lost entirely (apart from that, modifying the keys of a map or set actually is undefined behaviour).

结论:std::set不是一个选择,至少不是您要使用它的方式!

Conclusion: std::set is not an option, at least not the way you want to use it!

让我为您提出另一种方法:

Let me propose you another approach:

// yes, a vector...
// we'll need to maintain sorting ourselves...
std::vector<Player*> players;
// need pointers here, too, as pointers to objects
// (those within the teams!) might INVALIDATE on
// vector<Player> resizing!!!

std::map<std::string, std::vector<Player*>> teams;

players.push_back(new Player("a"));
teams["TeamA"].push_back(players.back());
teams["TeamB"].push_back(players.back());

players.push_back(new Player("b"));
teams["TeamA"].push_back(players.back());
teams["TeamC"].push_back(players.back());

现在让我们一支球队获胜:

Now let us one team win:

for(auto p : teams["TeamA"])
{
    ++p->wins;
}

好的,我们只是求助于

std::sort(players.begin(), players.end(), PlayerComp());

嘿,这只是StoryTeller的答案中的PlayerComp ...或者我们改用lambda:

Hey, this is just the PlayerComp from StoryTeller's answer... Or we use a lambda instead:

std::sort
(
    players.begin(), players.end(),
    [](Player const* x, Player const* y) { return *x < *y; }
);

最后,不要忘记再次删除播放器对象:

Finally, do not forget to delete your player objects again:

for(auto p : players)
{
    delete p;
}

如果使用智能指针,则可以跳过删除操作. G.像这样:

You can skip deletion, if you use smart pointers, e. g. like this:

std::vector<std::unique_ptr<Player>> players;

players.push_back(std::make_unique<Player>("a"));
teams["TeamA"].push_back(players.back().get());

for(auto p : teams["TeamA"])
    ++p->score;
std::sort
(
    players.begin(), players.end(),
    [](std::unique_ptr<Player> const& x, std::unique_ptr<Player> const& y) { return *x < *y }
);

以上假设玩家的向量具有玩家对象的唯一所有权,就像我的非智能指针解决方案一样.结果,如果删除了玩家的向量,则所有团队的玩家指针都将变为无效/晃动.在特定情况下合适,std::shared_ptr提供了一个值得一提的替代方法,它避免了指针悬空的可能性(价格是创建,分配和销毁过程中对象管理的开销,但是在访问智能指针时却不这样):

Above assumes the players' vector having unique ownership of the player objects, just as my non-smart-pointer solution does – in consequence, the teams' player pointers all get invalid/dangling, if the players' vector is deleted. Suitable in the specific case, an alternative worth to mention is provided by std::shared_ptr, which avoids the possibility of dangling pointers (price is some object management overhead during creation, assignment and destruction, not, however, while accessing the smart pointer):

std::vector<std::shared_ptr<Player>> players;
std::map<std::string, std::vector<std::shared_ptr<Player>>> teams;

players.push_back(std::make_shared<Player>("a"));
teams["TeamA"].push_back(players.back());


for(auto p : teams["TeamA"])
    ++p->score;
std::sort
(
        players.begin(), players.end(),
        [](std::shared_ptr<Player> const& x, std::shared_ptr<Player> const& y) { return *x < *y; }
);

这篇关于std :: set未检测到重复的自定义对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆