为何C++中查询空map会产生大量性能开销?
问题代码
#include <map> #include <sys/time.h> #include <stdio.h> #include <stdint.h> using namespace std; uint64_t timems() { timeval time; ::gettimeofday(&time, 0); return time.tv_sec * 1000 + time.tv_usec / 1000; } int main() { map<long, long> test_mm; long cc = 0; uint64_t t_start = timems(); for (int i = 0; i < 4000000; i++) { if (test_mm.find(i) != test_mm.end()){} // 查询空map cc++; } printf("time cost %ld ms\n", timems() - t_start); return 0; }
问题描述
上述代码在大循环中对空std::map执行查询操作,耗时约220ms;注释掉if (test_mm.find(i) != test_mm.end()){}语句后,循环仅耗时14ms。多次实验结果一致,使用gcc 4.8.5,编译命令为g++ test.cpp -o test,为何查询空map会有这么大的性能开销?
原因分析
std::map的底层实现逻辑:gcc 4.8.5中的std::map基于红黑树实现,即使是空map,find操作也会执行完整的红黑树查找流程框架——从根节点(空指针)开始,尝试对比目标键与节点键值,最终确认无匹配节点后返回end()迭代器。这个过程包含指针访问、键值比较、迭代器构造等多个步骤,并非直接返回结果。- 默认编译(-O0)的冗余开销:你使用的是默认编译选项(未开启优化),此时编译器不会做任何激进优化:
map::find作为成员函数,在-O0下通常不会被内联,每次调用都会产生栈帧创建、参数传递、返回值处理等函数调用开销;- 循环内的
find和end()调用会生成大量冗余指令,执行成本远高于简单的cc++自增操作。
- 空循环的执行效率:仅保留
cc++的循环本质是单一内存自增操作,指令数极少,CPU流水线可高效执行,因此耗时极低。 - 优化后的变化:如果开启编译优化(比如添加
-O2参数),编译器会识别出空map的find操作永远返回end(),进而将整个if语句优化掉,此时耗时会和空循环接近,可通过g++ -O2 test.cpp -o test验证。
内容的提问来源于stack exchange,提问作者Karate Yuan
相关产品推荐
相关产品推荐

