如果我有一个C ++函数声明:
int func(const vector<int> a)
用
替换它总是有益的int func(const vector<int> &a)
因为后者不需要复制a
来传递给函数吗?
答案 0 :(得分:4)
总的来说,是的。您应该始终通过引用传递大对象(或者将指针传递给它们,特别是如果您使用的是C)。
答案 1 :(得分:4)
就你所思考的效率而言,几乎总是如此。有时(据称)这可能会更慢,通常是基本或小的类型:
// copy x? fits in register: fast
void foo(const int x);
// reference x? requires dereferencing on typical implementations: slow
void foo(const int& x);
但是内联并不重要,加上你可以自己输入值;这只适用于通用模板函数。
然而,重要的是要注意您的转换可能并不总是有效,即因为您的函数获得了自己的数据副本。考虑这个更简单的例子:
void foo(const int x, int& y)
{
y += x;
y += x;
}
int v = 1;
foo(v, v); // results in v == 3
进行转型,然后得到:
void foo(const int& x, int& y)
{
y += x;
y += x;
}
int v = 1;
foo(v, v); // results in v == 4
因为即使您无法写入x
,也可以通过其他方式写入。这称为别名。虽然可能不是你所给出的例子的关注(尽管全局变量仍然可以别名!),但是要注意原则上的差异。
最后,如果你打算自己创建自己的副本,只需在参数列表中进行;编译器可以为您优化,特别是使用C ++ 11的右值引用/移动语义。
答案 2 :(得分:2)
大多数情况下它会更有效率 - 但是如果它发生func
需要制作自己的矢量副本并且破坏性地修改它,而无论它做什么无论如何,那么你也可以保存几行,让语言隐式地为你复制一个pass-by-value参数。可以想象,如果调用者之后实际上没有使用其向量副本,编译器可能会发现可以省略复制。
答案 3 :(得分:0)
正确。传递参考将避免复制。当涉及到副本而您实际上并不需要时,您应该使用引用。 (或者是因为你不打算修改这个值,在这种情况下,对原始文件进行操作很好并且你使用const引用,或者因为你做想要修改原文而不是它的副本,在这种情况下你使用非const引用。)
当然,这不仅限于函数参数。例如,看看这个函数:
std::string foo();
大多数人会以这种方式使用该功能:
std::string result = foo();
但是,如果您没有修改result
,那就更好了:
const std::string& result = foo();
没有复制。此外,与指针相反,引用保证foo()
返回的临时值保持有效并且不会超出范围(指向临时的指针是危险的,而对临时的引用是完全安全的。)
C ++ - 11标准通过使用移动语义来解决这个问题,但是大多数现有代码还没有使用这个新功能,因此尽可能使用引用是一个很好的习惯。
另外,请注意,在将临时工具绑定到引用时,必须注意临时生命周期,例如:
const int& f(const int& x)
{ return x; }
const int& y = f(23);
int z = y; /* OOPS */
关键是值为23的临时int
的生命周期未超出表达式绑定f(23)
到y
的结尾,因此尝试分配{{ 1}}到y
导致未定义的行为(由于悬空引用)。
请注意,当您处理POD类型(普通旧数据)时,例如z
或int
,您无法通过避免副本获得任何好处。通常,引用与char
或int
一样大(通常与指针一样大),因此通过引用复制long int
与复制int
相同本身。
答案 4 :(得分:0)
简而言之,是的。既然你无论如何也无法修改a
,那么你的所有函数体都可以做另一个副本,你也可以从const-reference中创建它。
答案 5 :(得分:0)
我可以想象通过值的传递可以更有效的一些原因: