【发布时间】:2013-04-28 12:00:24
【问题描述】:
我知道 STL 中使用的函数对象只是简单的对象,我们可以像函数一样操作它。那我可以说函数和函数对象的工作是一样的。如果是真的,那为什么我们应该使用函数对象而不是函数呢?
【问题讨论】:
我知道 STL 中使用的函数对象只是简单的对象,我们可以像函数一样操作它。那我可以说函数和函数对象的工作是一样的。如果是真的,那为什么我们应该使用函数对象而不是函数呢?
【问题讨论】:
主要的好处是对函数对象(函子)的调用通常是可内联的,而对函数指针的调用通常不是(主要示例是将 C 的 qsort 与 C++ 的 std::sort 进行比较)。对于非平凡的对象/比较器,C++ 应该会扼杀 C 的排序性能。
还有其他好处,例如,您可以将状态绑定或存储在函子中,而原始函数则无法做到这一点。
编辑 抱歉没有直接参考,但 Scott Meyers 声称在某些情况下有 670% 的改进: Performance of qsort vs std::sort?
编辑 2 带有性能说明的段落是这样的:
函数指针参数禁止内联的事实解释了一个 长期 C 程序员经常难以相信的观察结果: 当涉及到 C++ 的排序时,几乎总是让 C 的 qsort 感到尴尬 速度。当然,C++ 有函数和类模板来实例化和 调用看起来很有趣的 operator() 函数,而 C 使一个简单的 函数调用,但所有 C++“开销”都被吸收了 汇编。在运行时,sort 对其比较进行内联调用 函数(假设比较函数已被声明为内联 并且它的主体在编译期间可用)而 qsort 调用它的 通过指针进行比较函数。最终结果是那种 跑得更快。在我对一百万个双精度向量的测试中,它跑起来了 快 670%,但不要相信我的话,你自己试试吧。它的 在比较函数对象和实际函数时易于验证 作为算法参数,有一个抽象的好处。
-Scott Meyers "Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library" - Item 46
【讨论】:
inline 不是命令,它是对编译器/链接器的提示。
函数对象相对于函数的好处是它可以保持状态(来自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 wikipedia section 之前)...
【讨论】:
我认为函子最好的一点是它们可以在内部存储信息。在没有std::bind 的那些日子里,人们必须编写大量一元比较函数,以便将其传递给某些例程,例如remove_if。
【讨论】:
见http://cs.stmarys.ca/~porter/csc/ref/stl/function_objects.html。
STL 使用函数对象(函子)作为排序/搜索容器的回调。
函子是模板,因此更容易实现为类。试着用函数指针说greater<T>...考虑到 STL 中的容器也是模板。
【讨论】:
greater<int> 的类型是bool (*)(const int&, const int&),但是是的,除此之外你的答案很好。
template<typename T> typedef bool (*cmp)(const T&, const T&);?