【问题标题】:C++: std::map and std::set aren't ordered if using custom class (not pointers)C++:如果使用自定义类(不是指针),则不排序 std::map 和 std::set
【发布时间】:2021-10-27 13:50:44
【问题描述】:

这一定是非常愚蠢的事情,但我无法从中获得正面或反面。 这是测试代码。

#include <iostream>
#include <vector>
#include <limits>
#include <random>
#include <map>
#include <set>
#include <stdlib.h>
class value_randomized
{
public:
    double value;
    long random;
    value_randomized()
    {
        value=0;
        random=0;
    }
    /*
    bool operator<(const value_randomized& b) const
    {
        if (value<b.value) return true;
        return (random<b.random);
    }
    */
    friend bool operator<(const value_randomized& a, const value_randomized& b);
};
inline bool operator<(const value_randomized& a, const value_randomized& b)
{
    return (a.value<b.value)?true:(a.random<b.random);
}

int main(int argc, char *argv[])
{
    std::map<value_randomized,size_t> results;
    for (size_t i=0; i<1000; ++i)
    {
        value_randomized r;
        r.value=rand();
        r.value/=RAND_MAX;
        r.random=rand();
        results.insert(std::make_pair(r, i));
    }
    std::multiset<value_randomized> s;
    for (size_t i=0; i<1000; ++i)
    {
        value_randomized r;
        r.value=rand();
        r.value/=RAND_MAX;
        r.random=rand();
        s.insert(r);
    }
    return 0;
}

我已经尝试在类内和类外重载 operator

调试屏幕1

调试屏幕2

即使直接打印 multiset 的值也会给出一些明显无序的结果。这是第一个结果

(0.0515083,114723506)
(0.0995593,822262754)
(0.0491625,964445884)
(0.410788,11614769)
(0.107848,1389867269)
(0.15123,155789224)
(0.293678,246247255)
(0.331386,195740084)
(0.138238,774044599)
(0.178208,476667372)
(0.162757,588219756)
(0.244327,700108581)
(0.329642,407487131)
(0.363598,619054081)
(0.111276,776532036)
(0.180421,1469262009)
(0.121143,1472713773)
(0.188201,937370163)
(0.210883,1017679567)
(0.301763,1411154259)
(0.394327,1414829150)
(0.383832,1662739668)
(0.260497,1884167637)

显然我遗漏了什么,但是什么?

【问题讨论】:

  • 您的比较器错误(损坏的weak ordering)。请改用return std::tie(a.value, a.random) &lt; std::tie(b.value, b.random);
  • @Jarod42 它有效。谢谢。但是为什么逐个字段比较它不起作用呢?编辑:哦,我看到了链接。我要读它。再次感谢。
  • ...这是错误的,因为它会将(0.6, 1) 之类的东西视为小于(0.5, 2)。这不是字典顺序的实现方式。
  • (a.value&lt;b.value)?true:(a.random&lt;b.random); 等价于a.value &lt; b.value || a.random &lt; b.random。这意味着{0,1}{1,0} 都排在另一个之前,这是不可能的。
  • 现在我看到了问题所在。再次感谢,伙计们!

标签: c++ operator-overloading stdmap stdset


【解决方案1】:

你的比较函数没有按照Compare的要求做strict weak ordering

修复现有代码可以这样完成:

inline bool operator<(const value_randomized& a, const value_randomized& b) {
    if(a.value < b.value) return true;
    if(b.value < a.value) return false;
    return a.random < b.random;
}

或者更简单,使用std::tie:

inline bool operator<(const value_randomized& a, const value_randomized& b) {
    return std::tie(a.value, a.random) < std::tie(b.value, b.random);
}

【讨论】:

    猜你喜欢
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-27
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多