为何实验中C++ std::sort比C的qsort慢?与《C++编程语言》结论不符
你的实验结果和Stroustrup的结论看似矛盾,但核心是关闭编译器优化这个前提,加上测试场景的细节,共同导致了这个反直觉的结果。下面拆解具体原因:
1. 关闭优化直接废掉了std::sort的最大优势
Stroustrup的结论是基于开启编译器优化的工业级场景,这是关键前提。std::sort作为模板函数,最大的优势就是编译器可以对它做深度优化:
- 如果比较器是可内联的(比如lambda、inline函数、
std::less这类仿函数),编译器能直接把比较逻辑嵌入排序的核心循环,彻底消除函数调用的开销。 - 但你关闭了优化,同时用的是函数指针形式的比较器(
compFunc),这时候模板的优势完全发挥不出来:每次比较都要通过函数指针调用compFunc,而compFunc内部又调用strcmp,相当于一次比较有两层函数调用开销。
反观qsort,它本身就是基于函数指针的C风格排序,函数调用开销是其设计的固有部分,关闭优化后性能下降幅度远小于std::sort——qsort的实现是成熟的C代码,即使无优化,内部循环和递归逻辑也相对紧凑,而std::sort的模板代码在无优化下会产生大量冗余指令(比如迭代器的冗余检查、算法分支的额外判断)。
2. std::sort的自适应算法在无优化下开销更大
std::sort通常实现为内省排序(introsort):它结合快速排序、堆排序和插入排序的优点,会在递归深度超过阈值时自动切换到堆排序,避免快速排序的最坏情况。这种自适应逻辑在有优化时能带来更好的平均/最坏性能,但在关闭优化时,这些额外的逻辑(递归深度检查、算法分支切换)会产生显著的额外开销。
而qsort大多是传统的快速排序实现(部分会做简单优化,但没有introsort的自适应逻辑),逻辑更简单,无优化下的额外开销远小于std::sort。
3. 比较器的细微差异放大了开销
你给std::sort用的compFunc是:
bool compFunc(const char *c1, const char *c2) { return strcmp(c1, c2) < 0; }
而给qsort用的compFunc_2是直接返回strcmp的结果:
int compFunc_2(const void * a, const void * b) { const char *pa = *(char**)a; const char *pb = *(char**)b; return strcmp(pa, pb); }
虽然逻辑等价,但前者多了一步对strcmp返回值的比较判断。在无优化的情况下,这一步额外操作会被放大——1e6个元素的排序中,每一次比较都多一次判断,累积起来的开销不可忽视。
4. 额外补充:vector排序的性能差异
对于vector<string>的排序(测试用例[4]),std::sort需要移动/交换string对象。虽然string的交换是O(1)(本质是指针交换),但在无优化下,string的swap函数调用开销会被放大;而qsort处理的是char*指针,交换只是简单的指针赋值,开销极小,这也是[4]性能极差的原因。
验证建议
如果你打开VS的优化选项(比如O2),再把比较器换成可内联的lambda:
std::sort(vc2.begin(), vc2.end(), [](const char* c1, const char* c2) { return strcmp(c1, c2) < 0; });
你会发现std::sort的性能会反超qsort——编译器会把lambda的逻辑直接内联到sort的核心循环里,彻底消除函数调用开销,std::sort的算法优势就能完全体现出来。
内容的提问来源于stack exchange,提问作者K.Sam




