[英]Why no default hash for C++ POD structs?
I want to use a POD struct as a hash key in a map, eg 我想在地图中使用POD结构作为哈希键,例如
struct A { int x; int y; };
std::unordered_map<A, int> my_map;
but I can't do this, since no hash function is auto-generatable for such structs. 但是我不能这样做,因为没有哈希函数可以自动生成这样的结构。
As from the documentation , a possible implementation in your case would be: 从文档中可以看出,您的案例可能是:
#include<functional>
#include<unordered_map>
struct A { int x; int y; };
namespace std
{
template<> struct hash<A>
{
using argument_type = A;
using result_type = std::size_t;
result_type operator()(argument_type const& a) const
{
result_type const h1 ( std::hash<int>()(a.x) );
result_type const h2 ( std::hash<int>()(a.y) );
return h1 ^ (h2 << 1);
}
};
}
int main() {
std::unordered_map<A, int> my_map;
}
The compiler us not allowed to generate such a specialization because of the standard that does not define anything like that (as already mentioned in the comments). 编译器不允许生成这样的专门化,因为标准没有定义类似的东西(如评论中已经提到的)。
There is a method to generate hash for POD, like good old c
style. 有一种为POD生成哈希的方法,就像旧的c
风格一样。 Only for real POD with no any linked data on the outside of struct. 仅适用于结构外部没有任何链接数据的真实POD。 There is no checking of this requirements in code so use it only when you know and can guarantee this. 代码中没有检查此要求,因此只有在您知道并且可以保证这一点时才使用它。 All fields must be initialized (for example by default constructor like this A(), B() etc). 必须初始化所有字段(例如,默认构造函数,如此A(),B()等)。
#pragma pack(push) /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */
struct A { int x; int y; };
struct B { int x; char ch[8] };
#pragma pack(pop) /* restore original alignment from stack */
struct C { int x __attribute__((packed)); };
template<class T> class PodHash;
template<>
class PodHash<A> {
public:
size_t operator()(const A &a) const
{
// it is possible to write hash func here char by char without using std::string
const std::string str =
std::string( reinterpret_cast<const std::string::value_type*>( &a ), sizeof(A) );
return std::hash<std::string>()( str );
}
};
std::unordered_map< A, int, PodHash<A> > m_mapMyMapA;
std::unordered_map< B, int, PodHash<B> > m_mapMyMapB;
UPD: Data structure must be defined in data packing section with value of one byte or with pack attribute for prevent padding bytes. UPD:必须在数据打包部分中定义数据结构,其值为一个字节或具有pack属性以防止填充字节。
UPD: But I need to warn that replace deafult packing will make data loading/storing from/to memory for some fields little slowly, to prevent this need to arrange structure data fields with granularity that corresponding your (or most popular) architecture. UPD:但我需要警告,替换deafult包装会使某些字段的数据加载/存储到某些字段的速度很慢,以防止需要按照与您(或最常用)体系结构相对应的粒度排列结构数据字段。
I suggest that you can add by yourself additional unused fields not for using but for arrange fields in your data structure for best prformance of memory loading/storing. 我建议您可以自行添加其他未使用的字段,而不是用于数据结构中的排列字段,以获得最佳的内存加载/存储性能。 Example: 例:
struct A
{
char x; // 1 byte
char padding1[3]; // 3 byte for the following 'int'
int y; // 4 bytes - largest structure member
short z; // 2 byte
char padding2[2]; // 2 bytes to make total size of the structure 12 bytes
};
#pragma pack
is supported by, at least: #pragma pack
至少支持:
More flexible way is to declare comparision class and use it as template param of std::unordered_map
. 更灵活的方法是声明比较类并将其用作std::unordered_map
模板参数。
struct A { int x; int y; };
emplate<class T> class MyHash;
template<>
class MyHash<A> {
public:
size_t operator()(const A &a) const
{
result_type const h1 ( std::hash<int>()(a.x) );
result_type const h2 ( std::hash<int>()(a.y) );
return h1 ^ (h2 << 1);
}
};
std::unordered_map<CString,CString,MyHash> m_mapMyMap;
You may want another Hash for same objects. 您可能需要另一个Hash用于相同的对象。 Flexibility appear with code like this: 灵活性出现在这样的代码中:
std::unordered_map<CString,CString, *MyAnotherHas* > m_mapMyMap;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.