【问题标题】:overloading operator < for std::set confused me为 std::set 重载运算符 < 让我感到困惑
【发布时间】:2019-08-21 21:02:52
【问题描述】:

我知道我必须为 std::set 重载运算符

我用两个类重载运算符 this->unique_id_a_ == t.unique_id_a_。

然后我将相同的元素放入两个集合中。 最后我在集合中找到了一个元素。 一组可以找到,另一组找不到。 这个问题让我困惑了很久。

struct UniqueID {
    uint64_t unique_id_a_{0};
    uint64_t unique_id_b_{0};

    bool operator<(const UniqueID &t) const {
        if (this->unique_id_a_ < t.unique_id_a_) {
            return true;
        }
        if (this->unique_id_a_ == t.unique_id_a_ &&
            this->unique_id_b_ < t.unique_id_b_) {
            return true;
        }
        return false;
    }
};

struct UniqueIDWithBug {
    uint64_t unique_id_a_{0};
    uint64_t unique_id_b_{0};

    bool operator<(const UniqueIDWithBug &t) const {
        if (this->unique_id_a_ < t.unique_id_a_) {
            return true;
        }
        return (this->unique_id_b_ < t.unique_id_b_);
    }
};

// init data
std::set<UniqueID> _set = {
        {17303934402126834534u, 2922971136},
        {8520106912500150839u,  3118989312},
        {9527597377742531532u,  2171470080},
        {10912468396223017462u, 3972792320},
};
std::set<UniqueIDWithBug> _set_with_bug = {
        {17303934402126834534u, 2922971136},
        {8520106912500150839u,  3118989312},
        {9527597377742531532u,  2171470080},
        {10912468396223017462u, 3972792320}};

UniqueID _unique_id = {10912468396223017462u, 3972792320};
UniqueIDWithBug _unique_id_with_bug = {10912468396223017462u, 3972792320};

if (_set.find(_unique_id) == _set.end()) {
    std::cout << "_set not find" << std::endl;
}

if (_set_with_bug.find(_unique_id_with_bug) == _set_with_bug.end()) {
    std::cout << "_set_with_bug not find" << std::endl;
}

输出: _set_with_bug 找不到

【问题讨论】:

  • 是的,UniqueIDWithBug 是错误的。那你到底在问什么。你的问题缺少一些基本的东西。那将是一个实际的、具体的问题。
  • 我很困惑为什么 UniqueIDWithBug 是错误的,我认为 operator
  • 跟踪并比较UniqueIDWithBug a{1, 10} 和UniqueIDWithBug b{2,5}。执行a &lt; b 和b &lt; a 都返回true。那么如何定义排序呢?
  • 考虑使用unordered_set?
  • std::tie 使正确执行此操作变得容易得多。 return std::tie(unique_id_a_, unique_id_b_) &lt; std::tie(t.unique_id_a_, t.unique_id_b_); 是您在operator&lt; 中所需要的全部。想象一下扩展您的正确版本以手动处理 4 个变量。

标签: c++ algorithm sorting set std


【解决方案1】:

您定义用于std::set(和其他)的小于运算必须是有效的严格弱排序。

您的 UniqueIDWithBug 排序不是。

例如,考虑:

UniqueIDWithBug a{1, 10};
UniqueIDWithBug b{2, 5};

现在观察a &lt; b 和b &lt; a 都是真的。这只是一个快速演示,您没有严格的弱排序;确实,这根本不是命令!

所以你的程序有未定义的行为。 std::set 机制的内部假设一个有效的排序,但你的不是。在这种情况下,可观察到的结果是“未找到元素”。可能是“做披萨”。

构造一个好的严格弱排序可能很困难,但您已经完成了艰苦的工作,因为 UniqueID 的排序是正确的。

或者,完全放弃排序,定义一个哈希函数,然后切换到unordered_set。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多