在 C++ 中通过值传递还是通过常量引用传递更好?
我想知道哪个是更好的做法。我意识到通过常量引用传递应该在程序中提供更好的性能,因为您没有制作变量的副本。
通常建议最佳实践1对 所有类型 使用 pass by const ref ,除了内置类型(, ,等),迭代器和函数对象 __char``int``double(lambdas,派生自的类std::*_function)。
char``int``double
std::*_function
在移动语义 存在之前尤其如此。原因很简单:如果您按值传递,则必须制作对象的副本,并且除了非常小的对象外,这总是比传递引用更昂贵。
使用 C++11,我们获得了 移动语义 。简而言之,移动语义允许,在某些情况下,一个对象可以被传递“y值”而不复制它。特别是,当您传递的对象是 rvalue 时,就是这种情况。
就其本身而言,移动对象仍然至少与通过引用传递一样昂贵。然而,在许多情况下,一个函数无论如何都会在内部复制一个对象——即它将获得参数的 所有权 。2
在这些情况下,我们有以下(简化的)权衡:
“按值判断”仍然会导致对象被复制,除非对象是右值。在右值的情况下,可以移动对象,因此第二种情况突然不再是“opy, then move”而是“ove, then (potentially) move again”。
对于实现正确移动构造函数的大型对象(例如向量、字符串“”),第二种情况比第一种更有效 。 因此,如果函数拥有参数的所有权,并且对象类型支持高效移动 ,则建议使用按值传递。
历史注释:
事实上,任何现代编译器都应该能够找出何时按值传递代价高昂,并尽可能隐式地将调用转换为使用 const ref。
理论上。 在实践中,编译器可以——总是在不破坏函数的二进制接口的情况下改变它。在某些特殊情况下(当函数被内联时),如果编译器能够确定原始对象不会通过函数中的操作进行更改,则实际上会省略副本。
但总的来说,编译器可以确定这一点,而 C++ 中移动语义的出现使这种优化变得不那么重要了。
1例如,Scott Meyers, Effective C++ 。
2对于对象构造函数来说尤其如此,它可以接受参数并将它们存储在内部,以成为构造对象状态的一部分。