首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std::unordered_map查找()操作不能在GCC7中工作

std::unordered_map查找()操作不能在GCC7中工作
EN

Stack Overflow用户
提问于 2021-05-26 17:18:25
回答 1查看 174关注 0票数 2

我正在将我的c++应用程序从GCC4.7移植到GCC7,遇到了std::hash_map find()函数返回地图中存在的键的null结果的问题。

现有代码:

代码语言:javascript
复制
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结果的行为,甚至对于映射中存在的键也是如此。

示例运行在GCC7中的输出

代码语言:javascript
复制
Insert abc
Insert def
Insert xyz
Find def in cstmMap
output ptr (null)

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

代码语言:javascript
复制
template <typename T> class customMap : public std::unordered_map<const char*,T,std::hash<const char*>,eqfunc> {};

我注意到使用std::unordered_map的另一个奇怪行为是,在多个运行中,eqfunc没有以一致的模式执行。

示例1运行

代码语言:javascript
复制
Insert abc
Insert def
eqfunc in action def - abc
Insert xyz
Find def in cstmMap
eqfunc in action def - xyz
output ptr (null)

示例2运行

代码语言:javascript
复制
Insert abc
Insert def
eqfunc in action def - abc
Insert xyz
Find def in cstmMap
output ptr (null)

注意:--这是非常大的代码库,将const char *更改为std::string并不简单,需要做大量的工作。

我想知道是否有任何工作可以让它使用现有的const char *数据类型作为映射的键。如能对此提供任何帮助,将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-26 17:45:55

您已经发现std::hash<const char*>对实际指针进行散列,而不是它所指向的C字符串。有时,"def"和第二个"def"实际上具有相同的指针值。这取决于编译器如何优化它。

要使用C字符串,需要为C字符串提供一个散列函式。以下是一个例子:

代码语言:javascript
复制
#include <string_view>

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

并重新定义容器:

代码语言:javascript
复制
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;
};

添加了usingunordered_map构造函数使以更简单的方式构造映射成为可能:

代码语言:javascript
复制
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++之前使用C++17版本,则可以选择一个足够好的哈希函数来替换cstring_hash。这里有一个很有可能完成这项工作的人:

代码语言:javascript
复制
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;
    }
};
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67709794

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档