我知道 STL 中使用的函数对象只是简单的对象,我们可以像函数一样操作它。那我可以说函数和函数对象的工作是一样的。如果是真的,那为什么我们应该使用函数对象而不是函数呢?
4 回答
主要好处是对函数对象(仿函数)的调用通常是可内联的,而对函数指针的调用通常不是(主要示例是将 Cqsort
与 C++进行比较std::sort
)。对于非平凡的对象/比较器,C++ 应该会扼杀 C 的排序性能。
还有其他好处,例如您可以将状态绑定或存储在仿函数中,而您无法使用原始函数。
编辑 抱歉,没有直接参考,但 Scott Meyers 声称在某些情况下提高了 670%: qsort 与 std::sort 的性能?
编辑 2 带有表演说明的段落是这样的:
函数指针参数抑制内联的事实解释了长期 C 程序员经常难以相信的观察:在速度方面,C++ 的排序实际上总是让 C 的 qsort 感到尴尬。当然,C++ 具有用于实例化的函数和类模板,以及在 C 进行简单函数调用时调用的看起来很有趣的 operator() 函数,但是所有 C++“开销”都在编译过程中被吸收了。在运行时,sort 对其比较函数进行内联调用(假设比较函数已被声明为内联并且其主体在编译期间可用),而 qsort 通过指针调用其比较函数。最终结果是排序运行得更快。在我对一百万个双精度向量的测试中,它的运行速度提高了 670%,但不要相信我的话,你自己试试吧。
-Scott Meyers "Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library" - Item 46
函数对象相对于函数的好处是它可以保持状态(来自wikipedia):
#include <iostream>
#include <iterator>
#include <algorithm>
class CountFrom {
private:
int &count;
public:
CountFrom(int &n) : count(n) {}
int operator()() { return count++; }
};
int main() {
int state(10);
std::generate_n(std::ostream_iterator<int>(std::cout, "\n"), 11, CountFrom(state));
return 0;
}
常规函数不能像函数对象那样保持状态。如果我没记错的话,那是没有 lambda 和闭包的方法(在 C++11维基百科部分之前)...
我认为函子最好的一点是它们可以在内部存储信息。回到那些没有的日子里std::bind
,人们必须编写许多一元比较函数,以便可以将其传递给某些例程,例如remove_if
.
请参阅http://cs.stmarys.ca/~porter/csc/ref/stl/function_objects.html。
STL 使用函数对象(函子)作为排序/搜索容器的回调。函子是模板,因此更容易实现为类。试着greater<T>
用函数指针说……考虑到 STL 中的容器也是模板。