C++中大多数/所有 setter 函数的参数是否应该写为常量引用?
Should the parameters of most/all setter functions in C++ be written as const references?
例如
void SetNumbers(const double& a, const double& b)
{
m_a = a;
m_b = b
}
而不仅仅是
void SetNumbers(double a, double b)
{
m_a = a;
m_b = b
}
我听说它更快更安全,也许还有其他优点
在关联类型的复制/移动运算符不平凡的情况下,这两种方法并不等效。
假设你不关心这种区别(即,包括任何复制/移动在内的整个函数调用的效果在任何一种情况下都是相同的(,那么一般来说,这取决于 ABI 的机械细节:
- 小型类型可以有效地传递,通常在单个寄存器中传递。在这种情况下,没有按值传递的开销,因为副本隐式存在于 ABI 中。
- 无法在寄存器中传递的较大类型必须通过指针传递,即使"按值传递"也是如此,这意味着在按值传递的情况下会产生副本。
- 但是,如果函数是内联的,则此副本可能会消失,因为编译器可以看到该副本永远不会被访问。
- 按值传递可确保参数不能别名,这可能有助于更有效地优化函数,并且此效果有时可能非常大(可以使用
__restrict
等扩展来获得相同的引用效果(。 - 内联可以再次"否定"上述优势。
所以不幸的是,没有简单的答案。
仅考虑性能,合理的启发式可能是:
对于将在重要平台上的寄存器中传递的类型,首选按值传递。如果您不知道哪些类型将按值传递,则可以假设只有基元类型按值传递(但这通常是一个悲观的假设(。
对于创建副本的较大类型(如示例中所示(,对于 C++11 及更高版本可能仍首选按值传递,因为您可以在赋值中std::move
参数,对于支持移动的类型,当使用右值调用函数时,参数通常同样有效。对于不可移动的类型或当参数不是右值时,这两种方法都同样有效。
对于较大的类型,其中没有创建副本,我建议通过const
引用传递,除非在极少数情况下无法避免别名问题,在这种情况下需要副本。
这取决于参数类型。
如果值的大小是<= sizeof(void*)
,比如int
或float
(通常是double
(,最好按值传递它,这样它可能会被放入寄存器中,而不是在内存中查找。
如果它是一个大对象(如数组或字符串(,如果您打算从中复制数据,最好将其作为const &
(const 引用(。如果要移动或使用输入,最好将其作为&&
(右值引用(接收。
相关文章:
- 什么时候在C++中返回常量引用是个好主意
- 通过常量引用传递参数的矩阵模板类
- 在C++中使用非常量引用作为常量
- 具有常量引用参数的函数模板专用化
- 多个"常量引用"变量可以共享同一个内存吗?
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- 为什么常量方法可以采用非常量引用?
- 为什么当我们有常量引用时创建临时对象?
- 如何返回向量的常量引用?
- C++:常量引用参数
- 不同于按值传递和常量引用传递的程序集
- 为什么const_cast和static_cast常量引用没有效果?
- C++ 获取函数在常量引用中按值返回的结果
- 从 BubbleSort* 类型的右值初始化 'AssortedSorter&' 类型的非常量引用无效"
- C++ 在类中使用常量引用文本时 O2 内存泄漏
- 是否可以跨 dll 边界返回常量引用/指向 std::vectors?
- C++中大多数/所有 setter 函数的参数是否应该写为常量引用?
- 通过非常量引用参数修改常量引用参数
- 将常量引用传递给线程
- 为什么C++中没有常量引用,就像常量指针一样?