簡體   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