Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;字符串哈希是对字符串还是内存地址进行哈希?_C++_String_Dictionary_Hash_Std - Fatal编程技术网

C++ C++;字符串哈希是对字符串还是内存地址进行哈希?

C++ C++;字符串哈希是对字符串还是内存地址进行哈希?,c++,string,dictionary,hash,std,C++,String,Dictionary,Hash,Std,我以前从未研究过散列算法,当使用std::unordered_map时,我惊讶地发现散列函数(我想)实际上是散列内存地址,而不是字符串。如果我错了,请纠正我,但我只是通过更改一个原始字符串并将其添加到无序的_映射中发现了这一点,当内存地址(指针)相同时,它从未添加任何内容 在以下情况下,是否添加新键取决于std::string是否重新分配到内存的另一个区域: std::unordered_map<const char*, char*> myMap; std::string mySt

我以前从未研究过散列算法,当使用std::unordered_map时,我惊讶地发现散列函数(我想)实际上是散列内存地址,而不是字符串。如果我错了,请纠正我,但我只是通过更改一个原始字符串并将其添加到无序的_映射中发现了这一点,当内存地址(指针)相同时,它从未添加任何内容

在以下情况下,是否添加新键取决于std::string是否重新分配到内存的另一个区域:

std::unordered_map<const char*, char*> myMap;

std::string myString = "Key1";

myMap[myString.c_str()] = "someVal";    // <--- Adds a new key, size is now 1
myString = "Key2";
myMap[myString.c_str()] = "someVal";    // <--- Doesn't add a new key "Key2" didn't need to be reallocated
std::无序映射myMap;
std::string myString=“Key1”;

myMap[myString.c_str()]=“someVal”// 您错误地认为
constchar*
是一个字符串。它实际上是一个指针。因此,
std::unordered_map
使用指针(类型为
const char*
)作为键,
std::hash
对指针(对地址进行散列)的专门化作为散列键

如果要使用字符串作为键,应使用
std::string
,例如
std::unordered_map


编辑我还应该说,使用指针而不是字符串至少是危险的,但通常是不可能的。它不会像你想的那样。问题在于,字符串(字符序列)及其地址(指针)在程序的生命周期内不一定是成对的(尽管对于某些
const char*
对象可能是这样)。想想下面这些

std::unordered_map<const char*,int> map;
char str[11] = "bad";
map[str] = 2;           // hashes str = char*
auto x = map["bad"];    // hashes address of "bad"; x!=2
std::无序地图;
char str[11]=“坏”;
map[str]=2;//hashes str=char*
自动x=映射[“坏”];//散列“bad”的地址;x=2.

这说明了使用地址作为键并没有达到预期效果:如果查看的是标准的基本专门化,则无法从字符序列(
“bad”

中获取元素。
constchar*
没有专门化,因为它只是指向字符数组的指针。但是,任何指针类型都有专门化:

template< class T > struct hash<T*>;

由于键是
const char*
,因此代码运行正常。 尝试使用
std::string
作为键来获取所需的行为


所以:
std::无序映射myMap

使用指针作为键可能是一种解决方案,但仅适用于常量字符串-指针是最简单和最快的哈希。您可以使用不同的常量变量初始化无序映射,确保它们的生存期是适当的

C++字符串哈希是散列字符串还是内存地址?< /p> 这个问题实际上是关于平等和身份的,取决于你说“字符串”的意思

  • 相等。如果您指的是
    std::string
    类,则哈希与内存地址无关。字符串的实际内容是散列的。两个
    std::string
    实例相等,如果内容彼此相等,则生成相同的哈希

  • 标识。如果您指的是指向内存中某些字符的指针,那么不管存储在内存中的数据是什么,内存地址都会被散列。两个“字符串”是相同的,如果它们指向相同的内存位置,则生成相同的哈希


处理字符串时,几乎总是希望进行相等的比较,并鼓励使用
std::string
,因为代表相同数据的两个不同字符串实例应被视为相等,即使数据位于不同的内存地址,而
std::string
总是为您提供这些语义,无论是通过哈希还是通过简单的比较,如
myStr1==myStr2
[*]

哈希
char const*
char*
非常危险,因为您会遇到许多已实现的定义行为。字符串文字是这方面的主要示例。例如,考虑下面的程序:

#include <iostream>

int main()
{
    char const *a = "foo";
    char const *b = "foo";

    std::cout << reinterpret_cast<void const*>(a) << "\n";
    std::cout << reinterpret_cast<void const*>(b) << "\n";
}
您的代码还实现了定义的行为;不是因为文字,而是以不同的方式:

在以下情况下,是否添加新密钥取决于
std::string
是否重新分配到另一个内存区域:

std::unordered_map<const char*, char*> myMap;

std::string myString = "Key1";

myMap[myString.c_str()] = "someVal";    // <--- Adds a new key, size is now 1
myString = "Key2";
myMap[myString.c_str()] = "someVal";    // <--- Doesn't add a new key "Key2" didn't need to be reallocated
对。决不能从两个不同的
std::string
实例中获取
c_str()
指针,并假定这些指针完全相同,只是因为
std::string
实例相等

如果必须对字符串本身进行散列,这种方法会更慢吗

不。我向您提出挑战,让您拿出一个实际的用例,您可以实际测量差异。只有这样,它才会“慢”一点。否则,这就是老生常谈的过早优化

但还有更多。从技术上讲,散列单个地址应该比使用整个字符串内容(或其中很大一部分)来计算散列值要快,因为涉及的数据更多。这很明显。但我不确定您是否看到执行“昂贵”计算的必要性。这里面没有魔法。如果程序逻辑关心字符串的内容,则必须考虑单个字符。即使在理论上,您应该如何散列未读取的数据

或者,更一般地说,如何散列你没有的东西



[P>[*]巧合的是,在java中,一个非常常见的错误是不考虑这种区别,即<代码> STR1= = STR2< /COD>具有不同的语义,而不是代码> STR1。(Str2)。

代码> char */COD>不是字符串。是的,我知道,它是一个指向字符串的指针。我已经习惯将char*视为一个字符串,当您在需要字符串的地方传递它们时。那么std::string是唯一对实际字符串本身进行哈希处理的情况吗?我想在这种情况下,当在地图中查找时,哈希和查找都会变慢?想一想,如果是这样的话,难道不使用简单的poi吗
#include <iostream>
#include <unordered_map>

int main()
{
    char const *a = "foo";
    char const *b = "foo";

    std::unordered_map<char const*, char*> myMap;
    myMap[a] = "1";
    myMap[b] = "2";

    std::cout << myMap.size() << "\n"; // prints 1 or 2
}