簡體   English   中英

std::unordered_map find() 操作在 GCC7 中不起作用

[英]std::unordered_map find() operation not working in GCC7

I am working on porting my c++ application from GCC4.7 to GCC7 and ran into an issue where std::hash_map find() function returns null result for keys which are present in map.

現有代碼:

struct eqfunc {
  bool operator()(const char* const &s1, const char* const &s2) const {
    std::cout << "eqfunc in action " << s1 << " - " << s2 << std::endl;
    return strcmp(s1,s2) == 0;
  }
};

template <typename T> class customMap : public std::hash_map<const char*,T,std::hash<const char*>,eqfunc> {};

customMap<const char*> cstmMap;
std::cout << "Insert abc" << std::endl;
cstmMap["abc"] = "ABC";
std::cout << "Insert def" << std::endl;
cstmMap["def"] = "DEF";
std::cout << "Insert xyz" << std::endl;
cstmMap["xyz"] = "XYZ";

std::cout << "Find def in cstmMap" << std::endl;
string findString("def");
customMap<const char*>::iterator ptr = cstmMap.find((char *)findString.c_str());
LOG_INFO("output ptr %s", ptr);

這在 GCC4.7 平台上運行良好。 當我將代碼移植到 GCC7 時,我注意到 find() 返回null結果的行為,即使對於 map 中存在的鍵也是如此。

在 GCC7 中運行示例 output

Insert abc
Insert def
Insert xyz
Find def in cstmMap
output ptr (null)

std::hash_map更新為std::unordered_map也不起作用:

template <typename T> class customMap : public std::unordered_map<const char*,T,std::hash<const char*>,eqfunc> {};

我注意到使用std::unordered_map的另一個奇怪行為是eqfunc在多次運行中沒有以一致的模式執行

樣品 1 次運行

Insert abc
Insert def
eqfunc in action def - abc
Insert xyz
Find def in cstmMap
eqfunc in action def - xyz
output ptr (null)

樣品 2 運行

Insert abc
Insert def
eqfunc in action def - abc
Insert xyz
Find def in cstmMap
output ptr (null)

注意:這是非常大的代碼庫,將const char *更改為std::string並不簡單,需要大量工作。

我想知道是否有任何解決方法可以使其與地圖鍵的現有const char *數據類型一起使用。 對此的任何幫助將不勝感激。

您已經發現std::hash<const char*>散列實際指針 - 而不是它指向的 C 字符串。 有時"def"和第二個"def"實際上將具有相同的指針值。 這取決於編譯器如何優化它。

要使用 C 字符串,您需要為 C 字符串提供 hash 函子。 這是一個例子:

#include <string_view>

struct cstring_hash {
    size_t operator()(std::string_view str) const {
        return std::hash<std::string_view>{}(str);
    }
};

並重新定義容器:

template <typename T>
class customMap : public std::unordered_map<const char*, T, cstring_hash, eqfunc> {
    // To be able to use ctors:
    using std::unordered_map<const char*, T, cstring_hash, eqfunc>::unordered_map;
};

unordered_map構造函數的添加using使得可以以更簡單的方式構造 map:

int main() {
    customMap<const char*> cstmMap{
        {"abc", "ABC"},
        {"def", "DEF"},
        {"xyz", "XYZ"},
    };

    std::string findString("def");
    auto ptr = cstmMap.find(findString.c_str());
    std::cout << ptr->second << '\n';            // prints DEF
}

如果您使用的是 C++17 之前的 C++ 版本,您可以通過選擇足夠好的 hashA384F1AB54.8E16 來替換cstring_hash 這是一個可能完成這項工作的人:

namespace detail {
    static const auto S = // shift constant
        sizeof(size_t) < sizeof(uint64_t) ? 16u : 32u;
    static const auto C = // multiplication constant
        sizeof(size_t) < sizeof(uint64_t) ? 23456789u : 0xBB67AE8584CAA73Bull;
}

#if __cpp_constexpr >= 201304L
  #define RELAXEDCONSTEXPR constexpr
#else
  #define RELAXEDCONSTEXPR
#endif

struct cstring_hash {
    RELAXEDCONSTEXPR size_t operator()(const char *s) const {
        size_t h = 0;
        
        for(; *s; ++s) {
            h = h * detail::C + static_cast<unsigned char>(*s);
            h ^= h >> detail::S;
        }
        
        return h *= detail::C;
    }
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM