按值和引用传递仿函数对象(C ++)

时间:2011-11-19 18:43:58

标签: c++ templates

比较通用集成功能:

template <class F> double integrate(F integrand);

template <class F> double integrate(F& integrand);

template <class F> double integrate(const F& integrand);

每种的优点和缺点是什么? STL使用第一种方法(按值传递),是否意味着它是最普遍的方法?

3 个答案:

答案 0 :(得分:24)

函数对象通常应该很小,所以我不认为按值传递它们会明显地受到性能的影响(将它与函数在其体内的工作进行比较)。如果您通过值传递,您也可以从代码分析中获益,因为by值参数是函数的本地参数,优化程序可以判断何时何时不能从仿函数的数据成员中加载。

如果仿函数是无状态的,那么将它作为参数传递意味着根本没有成本 - 仿函数所采用的填充字节不必具有任何特定值(至少在GCC使用的Itanium Abi中)。使用引用时,您总是必须传递一个地址。

最后一个(const T&)的缺点是在C ++ 03中对原始函数不起作用,因为在C ++ 03中,如果你尝试应用{{{{{{{ 1}}到函数类型(并且是SFINAE情况)。当应用于函数类型时,更新近的实现会忽略const

第二个(const)有一个明显的缺点,就是你无法传递临时函子。

长话短说,除非我在具体案例中看到明显的好处,否则我通常会按价值传递它们。

答案 1 :(得分:7)

  

STL使用第一种方法(按值传递)

当然,标准库按值传递迭代器和仿函数。它们被假定(正确或错误地)复制起来很便宜,这意味着如果你编写一个复制费用昂贵的迭代器或仿函数,你可能必须找到一种方法来优化它。

但这仅仅是出于标准库使用仿函数的目的 - 大部分都是谓词,尽管还有像std::transform这样的东西。如果你正在集成一个函数,那就建议使用某种数学库,在这种情况下,我认为你可能更有可能处理带有大量状态的函数。例如,您可以有一个表示n阶多项式的类,其中n + 1个系数作为非静态数据成员。

在这种情况下,const引用可能会更好。在像transform这样的标准算法中使用这样的仿函数时,可以将它包装在通过指针执行间接的小类中,以确保它的复制成本低廉。

使用非const引用可能会让用户感到烦恼,因为它会阻止他们传递临时值。

答案 2 :(得分:3)

根据上下文,F应该是一个“可调用对象”(类似于自由函数或者定义了operator()的类)

现在,由于自由函数名称不能是L值,因此第二个版本不适合。 第三个假设F :: operator()为const(但如果需要改变F的状态则可能不是这种情况) 第一个是“自己的副本”,但要求F可以复制。

三者中没有一个是“普遍的”,但第一个最有可能在最常见的情况下工作。