为什么函数对象应该是值传递的

时间:2013-07-13 03:23:08

标签: c++ pass-by-value function-object

我刚读过经典着作“Effective C ++,3rd Edition”,在第20项中作者得出结论,内置类型,STL迭代器和函数对象类型更适合传值< / strong>即可。我很清楚内置和迭代器类型的原因,但是 为什么函数对象应该是值传递 ,因为我们知道它仍然是类型类型?

3 个答案:

答案 0 :(得分:19)

在典型情况下,函数对象很少或(更常见)没有持久状态。在这种情况下,通过值传递可能不需要实际传递任何东西 - &#34;值&#34;传递的内容基本上很少或仅仅是占位符#34;这是对象&#34;。

鉴于许多函数对象中的代码量很少,这导致了进一步的优化:编译器通常很容易扩展内联函数对象的代码,因此没有参数传递,也没有函数调用完全参与。

编译器可能能够在传递指针或引用时执行相同的操作,但它并不那么容易 - 更常见的是你会这样做最后创建一个对象,传递其地址,然后通过该指针调用该对象的函数调用操作符。

编辑:可能还值得一提的是,这同样适用于lambdas,因为它们实际上只是伪装的功能对象。你不知道类的名称,但是它们在紧邻的范围内创建了一个类,它重载了函数调用操作符,这是当你调用&#34; lambda。 [感谢@Mark Garcia。]

答案 1 :(得分:5)

按值传递函数对象的首要原因是标准库要求传递给其算法的函数对象是可复制的。 C ++11§25.1/ 10:

  

[注意:除非另有说明,否则允许将函数对象作为参数的算法进行复制   那些功能对象是自由的对象身份很重要的程序员应该考虑使用a   指向非复制实现对象的包装类,例如reference_wrapper<T>(20.8.3),   或一些等效的解决方案 - 后注]

其他答案在解释理由方面做得很好。

答案 2 :(得分:2)

来自Effective STL(因为你似乎喜欢Scott Meyers)第38项设计函数类来传递值

“在C和C ++中,函数指针都是按值传递的.STL函数对象是在函数指针之后建模的,因此STL中的约定是函数对象在传递给函数和从函数传递时都按值传递。”

这有一些好处和一些含义,比如@Jerry Coffin说,编译器可以做一些优化,比如内联代码以避免函数调用(你必须将你的仿函数标记为内联)。这种情况的一个很好的例子是qsort vs std :: sort性能比较,其中使用内联函子的std :: sort比qsort好很多,你可以在有效STL上找到更多关于它的信息,在那里广泛讨论并在几个中提到章节。

这也有一些含义,因为函数对象是按值传递和返回的,你必须确保你的对象有一个定义良好的复制机制,尺寸很小(否则它可能会变得昂贵),并且是单态的(因为按值传递多态对象可能会导致对象切片。