插入相同密钥时,自定义类的unordered_map不会导致错误

时间:2017-11-19 12:00:13

标签: c++ unordered-map

我正在试图找出使用unordered_map进行自定义类的一些要点。下面是我用来练习简单类Line的代码。我很困惑为什么Line2main()的{​​{1}}插入insert failed的{​​{1}} mLine1 {}}都是Line2。注意,因为我只比较3m函数中的第一个值(即operator==),因此此代码中的class LineLine1应该具有相同的值键。不应该插入已存在的密钥无效吗?有人可以向我解释原因吗?谢谢!

Line2

3 个答案:

答案 0 :(得分:6)

您的hashoperator ==必须满足他们当前违反的一致性要求。当根据==两个对象相等时,根据hash,它们的哈希码必须相等。换句话说,虽然不相等的对象可能具有相同的哈希码,但是相等的对象必须具有相同的哈希码:

size_t operator()(const Line& k) const  {
    return hash<float>()(k.getM());
}   

由于只比较一个组件是否相等,而忽略另一个组件,因此需要更改哈希函数以使用与确定相等性相同的组件。

答案 1 :(得分:0)

你在哈希中使用了“m”和“c”的值,所以如果“m”和“c”两者都相等,那么2“Line”实例会有相同的键,但事实并非如此在你的例子中。所以,如果你这样做:

Line line1 = Line(3.0,4.0);                                                                                                                                                                                                              
Line line2 = Line(3.0,4.0);                                                                                                                                                                                                              

t.insert({line1, 1});                                                                                                                                                                                                                                                                                                                                                                                                                                      
auto x = t.insert({line2, 2});                                                                                                                                                                                                           
if (x.second == false)                                                                                                                                                                                                                   
  cout << "insert failed" << endl;  

你会看到它会打印“插入失败”

答案 2 :(得分:0)

您可以随时使用自定义功能来比较插入时的键:

#include <iostream>
#include <unordered_map>

class Line {
private:
    float m;
    float c;
public:
    Line() { m = 0; c = 0; }
    Line(float mInput, float cInput) { m = mInput; c = cInput; }
    float getM() const { return m; }
    float getC() const { return c; }
};


struct hash
{
    size_t operator()(const Line& k) const 
    {
        return ((std::hash<float>()(k.getM()) ^ (std::hash<float>()(k.getC()) << 1)) >> 1);
    }
};

// custom key comparison
struct cmpKey
{
    bool operator() (Line const &l1, Line const &l2) const
    {
        return l1.getM() == l2.getM();
    }
};


int main()
{ 

    std::unordered_map<Line, int, hash, cmpKey> mymap; // with custom key comparisom

    Line line1 = Line(3.0, 4.0);
    Line line2 = Line(4.0, 5.0);
    Line line3 = Line(4.0, 4.0);

    auto x = mymap.insert({ line1, 1 });
    std::cout << std::boolalpha << "element inserted: " << x.second << std::endl;
    x = mymap.insert({ line2, 2 });
    std::cout << std::boolalpha << "element inserted: " << x.second << std::endl;
    x = mymap.insert({ line3, 3 });
    std::cout << std::boolalpha << "element inserted: " << x.second << std::endl;

    return 0;
}

打印:

element inserted: true
element inserted: true
element inserted: false