繁体   English   中英

为什么没有C ++ POD结构的默认哈希?

[英]Why no default hash for C++ POD structs?

我想在地图中使用POD结构作为哈希键,例如

struct A { int x; int y; };
std::unordered_map<A, int> my_map;

但是我不能这样做,因为没有哈希函数可以自动生成这样的结构。

  • 为什么C ++标准不需要POD结构的默认哈希?
  • 为什么编译器(特别是GCC 4.x / 5.x)提供这样的哈希值,即使标准没有强制要求呢?
  • 如何使用模板以可移植的方式为我的所有POD结构生成哈希函数(如果需要,我愿意做出语义假设)?

文档中可以看出,您的案例可能是:

#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;
}

编译器不允许生成这样的专门化,因为标准没有定义类似的东西(如评论中已经提到的)。

有一种为POD生成哈希的方法,就像旧的c风格一样。 仅适用于结构外部没有任何链接数据的真实POD。 代码中没有检查此要求,因此只有在您知道并且可以保证这一点时才使用它。 必须初始化所有字段(例如,默认构造函数,如此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:必须在数据打包部分中定义数据结构,其值为一个字节或具有pack属性以防止填充字节。

UPD:但我需要警告,替换deafult包装会使某些字段的数据加载/存储到某些字段的速度很慢,以防止需要按照与您(或最常用)体系结构相对应的粒度排列结构数据字段。

我建议您可以自行添加其他未使用的字段,而不是用于数据结构中的排列字段,以获得最佳的内存加载/存储性能。 例:

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至少支持:

更灵活的方法是声明比较类并将其用作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;

您可能需要另一个Hash用于相同的对象。 灵活性出现在这样的代码中:

std::unordered_map<CString,CString, *MyAnotherHas* > m_mapMyMap;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM