[英]unordered_map for custom class does not cause error when inserting the same key
I'm trying to figure out some points on using unordered_map
for custom class. 我试图弄清楚对自定义类使用unordered_map
几点。 Below are the codes I use to take exercise where I define a simple class Line
. 下面是我用来定义简单Line
类的代码。 I'm confused that why the insertion of Line2
in main()
does not make the program outputs insert failed
when the value of m
for Line1
and Line2
are both 3
. 我感到困惑的是,当Line1
和Line2
的m
值均为3
时,为什么在main()
中插入Line2
不会使程序输出insert failed
。 Note since I only compare the first value (ie m
) in the operator==
function in class Line
, thus Line1
and Line2
in this code should have the same key. 注意,由于我只比较class Line
operator==
函数中的第一个值(即m
),因此此代码中的Line1
和Line2
应该具有相同的键。 Shouldn't the insertion of an already existed key be invalid? 插入已经存在的键不应该是无效的吗? Could some one explain why to me? 有人可以向我解释为什么吗? Thanks! 谢谢!
#include<iostream>
#include<unordered_map>
using namespace std;
class Line {
public:
float m;
float c;
Line() {m = 0; c = 0;}
Line(float mInput, float cInput) {m = mInput; c = cInput;}
float getM() const {return m;}
float getC() const {return c;}
void setM(float mInput) {m = mInput;}
void setC(float cInput) {c = cInput;}
bool operator==(const Line &anotherLine) const
{
return (m == anotherLine.m);
}
};
namespace std
{
template <>
struct hash<Line>
{
size_t operator()(const Line& k) const
{
// Compute individual hash values for two data members and combine them using XOR and bit shifting
return ((hash<float>()(k.getM()) ^ (hash<float>()(k.getC()) << 1)) >> 1);
}
};
}
int main()
{
unordered_map<Line, int> t;
Line line1 = Line(3.0,4.0);
Line line2 = Line(3.0,5.0);
t.insert({line1, 1});
auto x = t.insert({line2, 2});
if (x.second == false)
cout << "insert failed" << endl;
for(unordered_map<Line, int>::const_iterator it = t.begin(); it != t.end(); it++)
{
Line t = it->first;
cout << t.m << " " << t.c << "\n" ;
}
return 1;
}
Your hash
and operator ==
must satisfy a consistency requirement that they currently violate. 您的hash
和operator ==
必须满足它们当前违反的一致性要求。 When two objects are equal according to ==
, their hash codes must be equal according to hash
. 当两个对象根据==
相等时,它们的哈希码必须根据hash
相等。 In other words, while non-equal objects may have the same hash code, equal objects must have the same hash code: 换句话说,虽然不相等的对象可能具有相同的哈希码,但是相等的对象必须具有相同的哈希码:
size_t operator()(const Line& k) const {
return hash<float>()(k.getM());
}
Since you compare only one component for equality, and ignore the other component, you need to change your hash function to use the same component that you use to decide the equality. 由于您仅比较一个组件的相等性,而忽略另一个组件,因此需要更改哈希函数以使用用于确定相等性的相同组件。
you are using both the values of "m" and "c" in you hash, so 2 "Line" instances would have the same key if both their "m" and "c" are equal, which is not the case in your example. 您在哈希中同时使用了“ m”和“ c”的值,因此,如果两个“ Line”实例的“ m”和“ c”相等,则它们将具有相同的键,在您的示例中情况并非如此。 So if you do this : 因此,如果您这样做:
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;
you'll see that it will print "insert failed" 您会看到它将打印“插入失败”
You can always use custom function to compare the keys upon insertion: 您始终可以使用自定义功能在插入时比较键:
#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;
}
Prints: 印刷品:
element inserted: true
element inserted: true
element inserted: false
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.