Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么函数对象应该按值传递 我刚刚读过经典的《有效C++,第三版》,在第20条中,作者得出结论:内置类型、STL迭代器和函数对象类型更适合于通过值< /强>。我可以很好地理解内置类型和迭代器类型的原因,但是为什么函数对象应该按值传递呢,因为我们知道它是类类型?_C++_Pass By Value_Function Object - Fatal编程技术网

为什么函数对象应该按值传递 我刚刚读过经典的《有效C++,第三版》,在第20条中,作者得出结论:内置类型、STL迭代器和函数对象类型更适合于通过值< /强>。我可以很好地理解内置类型和迭代器类型的原因,但是为什么函数对象应该按值传递呢,因为我们知道它是类类型?

为什么函数对象应该按值传递 我刚刚读过经典的《有效C++,第三版》,在第20条中,作者得出结论:内置类型、STL迭代器和函数对象类型更适合于通过值< /强>。我可以很好地理解内置类型和迭代器类型的原因,但是为什么函数对象应该按值传递呢,因为我们知道它是类类型?,c++,pass-by-value,function-object,C++,Pass By Value,Function Object,在典型情况下,函数对象几乎没有持久状态,或者(通常)没有持久状态。在这种情况下,通过值传递可能根本不需要实际传递任何东西——传递的“值”基本上只是“this is the object”的占位符 考虑到许多函数对象中的代码量很小,这将导致进一步的优化:编译器通常很容易内联扩展函数对象的代码,因此不会传递任何参数,也不会涉及任何函数调用 当您传递一个指针或引用时,编译器可能也能做到这一点,但这并不是那么容易——更常见的情况是,您最终会创建一个对象,传递其地址,然后通过该指针调用该对象的函数调用运算

在典型情况下,函数对象几乎没有持久状态,或者(通常)没有持久状态。在这种情况下,通过值传递可能根本不需要实际传递任何东西——传递的“值”基本上只是“this is the object”的占位符

考虑到许多函数对象中的代码量很小,这将导致进一步的优化:编译器通常很容易内联扩展函数对象的代码,因此不会传递任何参数,也不会涉及任何函数调用

当您传递一个指针或引用时,编译器可能也能做到这一点,但这并不是那么容易——更常见的情况是,您最终会创建一个对象,传递其地址,然后通过该指针调用该对象的函数调用运算符

编辑:可能还值得一提的是,lambda也是如此,因为它们实际上只是伪装的函数对象。您不知道该类的名称,但它们在紧邻的作用域中创建了一个类,该类重载函数调用运算符,这是在“调用”lambda时调用的。[谢谢@Mark Garcia.]

来自有效STL(因为您似乎喜欢Scott Meyers)第38项为传递值设计函子类

在C++和C++函数中指针都是通过值传递的。STL函数对象是在函数指针之后建模的,所以STL中的约定是函数对象在传递给函数时也是通过值传递的。 这有一些好处和含义,就像@Jerry Coffin说的,编译器可以进行一些优化,比如内联代码以避免函数调用(必须将函子标记为内联)。这种情况的一个很好的例子是qsort与std::sort的性能比较,其中使用内联函子的std::sort的性能要比qsort好得多,您可以在有效的STL上找到更多关于这方面的信息,其中有很多章节对此进行了详细讨论和提及

这也有几个含义,因为函数对象是通过值传递和返回的,所以您必须确保对象具有定义良好的复制机制、较小的大小(否则可能会很昂贵)和单态(因为通过值传递多态对象可能会导致对象切片).

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

[注意:除非另有规定,否则允许复制以函数对象为参数的算法 那些对象身份很重要的程序员应该考虑使用 指向非复制实现对象的包装器类,如
reference\u wrapper
(20.8.3), 或者一些等效的解决方案。-结束注释]


其他答案在解释基本原理方面做得很好。

+1阅读有效的C++函数对象应该很少有太多开销。至少,现在有了移动语义,它更符合逻辑(一般来说,所有对象)。感谢您的解释,“内联优化”部分给我留下了深刻的印象。我的工作经验表明,广泛使用
boost::bind
会导致复制成本高昂的函数对象。它似乎在绑定深度上呈指数级增长(绑定一个内部有绑定回调的回调等),“在典型情况下,函数对象将很少或(更常见的是)没有持久状态”我不会争论什么是典型的或非典型的,但如果我正在编写一个需要做出这种设计选择的库函数,那么,我不应该选择适用于所有调用方的方式,不管它们的函数对象的状态是很少的、没有状态的还是很多状态的吗?似乎这样做的方法是通过参考。迈尔斯的有效系列在中国非常流行:-)。另外,感谢您解释了std::sort和std::qsort之间的区别。