【问题标题】:Why is operator< overloading necessary for STL set containing custom objects, instead of operator==为什么包含自定义对象的 STL 集需要 operator< 重载,而不是 operator==
【发布时间】:2020-12-26 16:39:48
【问题描述】:

我正在使用 C++11,我想使用 set 来存储我的自定义对象,因为我需要一个容器,它可以过滤具有相同值的元素。

这是我的自定义对象的类:

struct Ele
{
    int a, b, c;
}

据我了解,我需要重载函数operator==,因为set需要过滤具有相同值的元素。

但是,在阅读了这个链接:How do i insert objects into STL set之后,似乎我需要重载operator&lt;,而不是operator==

所以我的代码是这样的:

struct Ele {
    int a, b, c;
    friend bool operator<(const Ele &e1, const Ele &e2);
};
bool operator<(const Ele &e1, const Ele &e2)
{
    if (e1.a < e2.a) {
        return true;
    }
    if (e1.a == e2.a) {
        if (e1.b < e2.b) {
            return true;
        }
        if (e1.b == e2.b) {
            if (e1.c < e2.c) {
                return true;
            }
            return false;
        }
        return false;
    }
    return false;
}

并进行如下测试:

set<Ele> myset;
Ele e1;
e1.a = 1;
e1.b = 2;
e1.c = 3;
Ele e2;
e2.a = 1;
e2.b = 2;
e2.c = 3;
myset.insert(e1);
myset.insert(e2);
cout << myset.size() << endl;

嗯,输出是1,而不是2,这意味着e2的插入失败,因为e2的值与e1的值相同。

现在我很困惑。

据我了解,operator&lt; 只是告诉编译器如何理解e1 &lt; e2,编译器怎么知道如何理解e1 == e2?如果我想设置这样的规则怎么办:e1 == e2 only if e1.a == e2.b &amp;&amp; e1.b == e2.c &amp;&amp; e1.c == e2.a?

【问题讨论】:

  • Some reading,特别是严格的弱排序以及equiv是如何定义的。
  • 因为std::set是一个有序容器,它需要知道元素之间的相对顺序,而不仅仅是两个元素相等? (请注意,&lt; 也可用于检查是否相等。)
  • 我们刚刚获得了 C++20,我们将获得 operator&lt;=&gt;。这可以做所有的比较。
  • 如果你有 operator == 那么它对标准容器无效,因为标准容器期望如果 A==B 那么 B==A

标签: c++ c++11 stl set


【解决方案1】:

== 本身不足以定义排序,而 &lt; 是。此外,所有其他关系运算符都可以转换为 operator&lt;,只要允许您否定结果。

例如,a == b if !(a &lt; b)!(b &lt; a)

&lt; 是一种自然选择,因为按升序思考事物是很自然的。 &gt; 可以被选中,但不会那么容易处理。

【讨论】:

  • &lt;&lt;=&gt;&gt;= 中的任何一个都可以用来合成一个订单,但 &lt; 是“最”自然的升序命令。 &gt; 降序很自然
【解决方案2】:

operator&lt; 是必需的,因为标准内部隐含地要求std::map 是一个需要元素之间某种排序的树状数据结构。请注意,仅使用operator&lt; 即可生成所有比较函数。看看:

a == b <==> !(a < b) && !(b < a)
a > b <==> b < a
a >= b <==> !(a < b)

等等

【讨论】:

    【解决方案3】:

    可以使用==(和!)确保唯一性,但它的效率低于使用&lt;std::set)或哈希函数(std::unordered_set) .

    考虑插入。只有==,您必须比较每个元素以验证您还没有相等的元素。 std::set 的元素保持有序,因此 insert 进行二进制搜索,查看的元素要少得多。 std::unordered_set 的元素根据哈希值保存在桶中,因此查找只需要搜索桶,而不是整个集合。

    Bathsheba's 回答中所述,您可以从&lt; 合成一个相等函数

    【讨论】:

      【解决方案4】:

      其他答案已经指出std::set 需要元素的排序,这需要为类型定义operator&lt;。如果不关心排序,只关心唯一性,可以使用std::unordered_set

      另外,这里有一种更简洁的方法来实现比较:

      bool operator<(const Ele &e1, const Ele &e2)
      {
        return std::tie(e1.a, e1.b, e1.c) < std::tie(e2.a, e2.b, e2.c);
      }
      

      【讨论】:

        猜你喜欢
        • 2018-07-30
        • 2014-08-30
        • 2011-08-30
        • 2018-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-06
        • 1970-01-01
        • 2020-09-20
        相关资源
        最近更新 更多