为什么 C++ 映射说结构存在,而不存在?

Why Does C++ Map Say That Struct Exists When Doesn't?

提问人:zrli 提问时间:11/5/2023 最后编辑:JaMiTzrli 更新时间:11/5/2023 访问量:234

问:

我有一个名为 foo 的结构,还有一个名为 mp 的映射,但出于某种原因,当我插入 {5, 0, 3} 并查询 {5, 3, 0} 时,映射说它包含 {5, 3, 0},而实际上它没有:

#include <bits/stdc++.h>

using namespace std;

struct foo {
    int v1, v2, v3;
    friend bool operator<(const foo &a, const foo &b) {
        return a.v1 < b.v1;
    }
    friend bool operator==(const foo &a, const foo &b) {
        return (a.v1 == b.v1) && (a.v2 == b.v2) && (a.v3 == b.v3);
    }
};

int main() {    
    map<foo, int> mp;
    mp[{5, 0, 3}] = 1;
    if(mp[{5, 3, 0}]) {
        cout << "YES\n";
    } else {
        cout << "NO\n";
    }

    return 0;
}

输出:

YES

有谁知道为什么我的代码会这样做?如果是这样,我需要更改什么?

C++ 标准映射

评论

1赞 Ted Lyngmo 11/5/2023
无关:你可以用mt19937_64 rng(std::random_device{}());
5赞 user4581301 11/5/2023
如果在地图中找不到该密钥,[] 会将该密钥添加到地图中。
5赞 Some programmer dude 11/5/2023
请阅读 为什么我不应该 #include < bits/stdc++.h>?为什么“使用命名空间 std;”被认为是不好的做法?还要注意的是,所有这些全局类型别名和全局变量也是一个非常糟糕的习惯。你永远不应该在你给老师、面试或一般工作的“真实”代码中使用这些东西。
4赞 Some programmer dude 11/5/2023
我们不知道你的背景。据我们所知,您可能正在使用糟糕的网站来实际尝试学习基础知识或编程,这不是它们的目的。似乎这些网站上的所有例子都很糟糕,只能用作坏例子。习惯往往会坚持下去,尤其是坏习惯。最好养成良好的习惯,从一开始就写出漂亮、好和干净的代码。即使是所谓的“比赛”。
8赞 Retired Ninja 11/5/2023
operator<仅检查 so 并且是等效的。 从未使用过。v15,0,35,3,0operator==

答:

6赞 JaMiT 11/5/2023 #1

比较运算符与相等运算符不匹配。A 不使用相等运算符;它使用“小于”。如果两者都不是,则地图会考虑和等效。在您的情况下:std::mapa < bb < aab

  • foo{5, 0, 3} < foo{5, 3, 0}是因为是假的。false5 < 5
  • foo{5, 3, 0} < foo{5, 0, 3}是因为是假的。false5 < 5

因此,地图认为这些对象是等价的。因此,找到您刚刚设置为 1 的 map 元素,因此它是一个真实值。mp[{5, 3, 0}]

为了得到你想要的结果,你需要考虑所有三个成员,而不仅仅是.operator<v1

例如:

    friend bool operator<(const foo &a, const foo &b) {
        if (a.v1 != b.v1)
            return a.v1 < b.v1;
        if (a.v2 != b.v2)
            return a.v2 < b.v2;
        return a.v3 < b.v3;
    }

或者(正如PaulMcKenzie所建议的)更简单地说:

    friend bool operator<(const foo &a, const foo &b) {
        return std::tie(a.v1, a.v2, a.v3) < std::tie (b.v1, b.v2, b.v3);
    }

评论

0赞 zrli 11/5/2023
我将如何做到这一点,以便将所有三个成员都占为止?由于我刚刚尝试了这个,它至少返回了正确的答案,但仍然有某种导致 TLE 的问题: struct foo { int v1, v2, v3; friend bool operator<(const foo &a, const foo &b) { if(a.v1 < b.v1) { return true; else if(a.v2 < b.v2) { return true<;
0赞 PaulMcKenzie 11/5/2023
@zrli -- 在主要评论部分查看我的评论。
0赞 zrli 11/5/2023
@PaulMcKenzie OK
0赞 JaMiT 11/5/2023
@zrli -- 当 和 其他字段的值导致运算符返回 时,就会发生此处的错误。使用(正如 PaulMcKenzie 所建议的)可以让你不必记住这个比较函数可能出错的所有方式(以及其他人已经遇到过数百次)的方式。if(a.v1 < b.v1) { return true; } else if(a.v2 < b.v2) { return true; } else if(a.v3 < b.v3) { return true; } return false;a.v1 > b.v1truestd:tie
0赞 zrli 11/5/2023
@JaMiT是的,这个问题现在已经解决了!您是否偶然知道结构体是否比元组更耗时?
2赞 gbjbaanb 11/5/2023 #2
int v1, v2, v3;
friend bool operator<(const foo &a, const foo &b) {
    return a.v1 < b.v1;
}

首先,这只检查第一个值。所以 5,0,0 将被视为相同的 a 5,9,9 等。

   if(mp[{5, 3, 0}])

这与你的想法不同。如果不存在,Operator[] 将创建一个新条目。但是,当它插入值 0 时,您的 if 语句给出了您期望的结果,但它没有按照您期望的方式执行。这种“副作用”很糟糕,这就是错误蔓延的地方。您应该改用 map.find() 之类的方法