与将条件作为模板参数传递给sort()的比较导致比将条件函数指针传递给qsort()更少的开销?

时间:2014-09-22 01:41:57

标签: c++ sorting

在Stroustrup的The C++ programming language , Page 431中,当他讨论标准库的设计时,他说,

  

例如,将比较标准构建为排序函数是不可接受的,因为它是相同的   数据可以根据不同的标准进行排序。这就是为什么C标准库qsort()将比较函数作为参数而不是依赖于固定的东西,比如<运营商。另一方面,每次比较的函数调用所产生的开销会使qsort()成为进一步构建库的构建块。

以上这些对我有意义。但在第二段中,他说,

  

这种开销严重吗?在大多数情况下,可能不是。但是,函数调用开销可以   主导某些算法的执行时间并使用户寻求替代方案。通过§13.4中描述的模板参数提供比较标准的技术解决了这个问题   问题。

在§13.4中,比较标准被定义为具有静态成员函数的类(进行比较)。当这些类用作模板参数时,仍然通过其静态成员函数进行比较。在我看来,仍然会有调用静态成员函数的开销。

Stroustrup的意思是什么?

3 个答案:

答案 0 :(得分:8)

std::sort是一个功能模板。在编译期间,将为每个类型和比较运算符创建单独的sort实例。并且因为对于每个sort实例化,类型和比较器在编译时是已知的,这允许内联比较器函数,因此避免了函数调用的成本。

答案 1 :(得分:3)

理论上没有sort需要比qsort更快的原因。有些编译器甚至会将函数指针内联到函数中,例如' qsort:我相信我已经看过gcc或clang这样做(不是qsort),甚至在功能定义位于不同的cpp文件中也是如此。

重要的是,sort将函数对象作为类型和实例传递。生成每种类型的不同函数:template s是函数的工厂。在调用它时,调用的确切函数对于每个这样的函数实例都很容易确定,因此内联很简单。

可以对函数指针执行相同的操作,但需要从调用qsort的点开始内联,并仔细跟踪函数指针的不变性,并知道它是从哪个函数开始的。这在实践中比上述机制脆弱得多。

类似问题出现在元素步幅中(当sort数组时显然是静态的,使用qsort时更难处理)等。

答案 2 :(得分:1)

通过指针调用函数有两个开销:指针解除引用和函数调用开销。这是一个运行时过程。

模板实例化由编译器完成。指针解除引用被消除,因为显然没有指针。函数调用开销由编译器通过内联调用进行优化。