c++ - 在 MSVC++ 的 STL 中插入 std::unordered_map 两次调用散列函数,糟糕的设计还是特殊原因?

标签 c++ c++11 visual-c++ stl

对于这段代码:

#include<unordered_map>
#include<iostream>
using namespace std;
struct myhash {
    unsigned operator()(const unsigned&v)const {
        cout<<"Hash function is called:"<<v<<endl;
        return v;
    }
};
unordered_map<unsigned,unsigned,myhash>mp;
int main() {
    for (unsigned i=0;i<3;++i) {
        cout<<"Visiting hash table:"<<i<<endl;
        ++mp[i];
    }
}

使用 g++ 时,输出结果不足为奇:

Visiting hash table:0
Hash function is called:0
Visiting hash table:1
Hash function is called:1
Visiting hash table:2
Hash function is called:2

但是 MSVC++(2015) 的输出让我震惊:

Visiting hash table:0
Hash function is called:0
Hash function is called:0
Visiting hash table:1
Hash function is called:1
Hash function is called:1
Visiting hash table:2
Hash function is called:2
Hash function is called:2

进一步的测试表明,当在 unordered_map 中插入一个新元素时,MSVC++ 的 STL 调用哈希函数两次,如果该元素已经在映射中则调用一次。

我对这种行为感到很奇怪,因为我认为在大多数情况下缓存结果比再次调用哈希函数要快得多(如果实现确实需要两次使用哈希值)。或者更好的是,我认为只是使用哈希函数一次来查找元素的桶,并且以下例程与哈希值无关。

不过,由于STL的作者在C++方面的经验比我丰富很多,不知道他们这样实现是不是有什么特殊的原因?这只是一个糟糕的设计还是由我不知道的某些原因造成的?

最佳答案

在 Release 模式下也观察到 VS2012 的相同行为。

区别在于 un_orderedmap 的实现。 如果您调试并进入:Microsoft Visual Studio 11.0\VC\include\unordered_map,对函数调用运算符的第一次调用是检查键是否已存在于映射中。 第二次调用是在插入 map 期间进行的(前提是未找到键)- 在 3 次迭代之后 map 具有 ((0,1), (1,1), (2,1))

关于c++ - 在 MSVC++ 的 STL 中插入 std::unordered_map 两次调用散列函数,糟糕的设计还是特殊原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33839092/

相关文章:

c++ - 使用Vector实现Stack的问题

c++ - 枚举处的 Visual Studio 编译器错误

c++ - 包含预编译二进制文件与手动编译二进制文件不同的头文件的正确方法

c++ - 我什么时候使用哪种指针?

c++ - cv::split 或 Eigen::Stride:哪个更有效地将多 channel 矩阵从 OpenCV 映射到 Eigen 结构

c++ - 监控 C++11 和 C++03 中的类实现?

c++ - Recvfrom() 挂起——当服务器关闭时如何处理这个问题

C++ 'true' 和 'false' 关键字在 Visual C++ 6.0 中突然不正确或错误

c# - System.Net.Sockets 发送与 stdcall :send

C++异常处理,错误