我知道当您想更改原始变量的值时,您通过引用传递给 C++ 中的函数。但是,当您希望程序更高效并且不想更改传递给函数的变量中的任何内容时,您也可以通过引用传递,只需将其设为 const。我的问题是,如果它比仅传递变量并让编译器在函数范围内创建一个新变量更有效,为什么不总是让你的函数接受由 const 引用传递的变量?为了扩展这个问题,一个函数需要复制一个通过参数传递的变量的情况是什么?
3 回答
当参数按值传递时,它是可修改的,并且可以省略复制它。例如,实现赋值运算符的规范方法如下所示:
T& T::operator= (T value) {
value.swap(*this);
return *this;
}
乍一看,它可能看起来效率低下,因为T
正在复制 a。但是,无论如何它都会被复制,即,如果需要一个副本,将以任何一种方式创建一个:
T& T::operator= (T const& value) {
T(value).swap(*this); // has to do a copy right here
return *this;
}
但是,对于第一个版本,可能根本不创建副本,例如
T f() { return T(); }
// ...
T x = ...;
x = f();
当将其结果分配给f()
类型T
时x
,编译器可能会决定它不需要复制结果,f()
而是直接将其传递给赋值运算符。在这种情况下,如果赋值运算符采用const&
编译器的参数,则必须在赋值运算符内创建一个副本。在按值获取参数的实现中,它可以省略副本!实际上,return fromf()
已经可以省略副本,即调用 tof()
和下面的赋值可能只涉及对象的默认构造!...对于许多现代编译器来说,确实如此!
换句话说:如果您需要复制一个参数,通过值传递它可能会避免创建副本的需要。此外,您可以std::move()
使用值参数,但不能使用const&
参数。
但是,当您希望程序更高效并且不想更改传递给函数的变量中的任何内容时,您也可以通过引用传递,只需将其设为 const。
这是错的。传递基本类型(int、float、char....)的参数比通过引用传递它们更有效。const & 在传递 BIG OBJECT 方面更有效。因为引用本质上是一个对象的别名,编译器需要处理更多的信息。
引用本质上是一种特殊的指针契约,其回报是一些语法糖和简单性。在函数体内,编译器可以自由地消除引用,但是当它们作为参数传递时,实际上传递的是指针。
结果是,使用参考可能会产生额外成本。
void func(int& i) {
int j = i; // secretly a dereference
// ...
}
产生与
void func(int* i) {
int j = *i;
// ...
}
本地的、方便的引用通常可以被优化掉,但引用参数必须至少在第一次使用时被取消引用。