据我理解:当你通过值传递时,函数会生成传递参数的本地副本并使用它;当函数结束时,它超出范围。当您通过const引用时,该函数使用对无法修改的传递参数的引用。但是,我不明白为什么会选择一个而不是另一个,除非需要修改和返回参数。如果你有一个无效的函数,那么为什么选择一个呢?
编辑:所以基本上通过const引用传递避免复制对象。那么在什么情况下复制对象好呢?我的意思是,如果它始终优化性能,为什么不一直使用const引用呢?
答案 0 :(得分:48)
有两个主要考虑因素。一个是复制传递对象的费用,第二个是当对象是本地对象时编译器可以做出的假设。
E.g。在第一种形式中,在f
的正文中,不能假设a
和b
不引用同一个对象;所以在写入a
之后必须重新阅读b
的值,以防万一。在第二种形式中,a
不能通过写入b
来更改,因为它是函数的本地,因此这些重新读取是不必要的。
void f(const Obj& a, Obj& b)
{
// a and b could reference the same object
}
void f(Obj a, Obj& b)
{
// a is local, b cannot be a reference to a
}
例如:在第一个示例中,编译器可以假设在进行不相关的调用时本地对象的值不会改变。如果没有关于h
的信息,编译器可能无法知道该函数对(通过引用参数)引用的对象是否未被h
更改。例如,该对象可能是由h
修改的全局状态的一部分。
void g(const Obj& a)
{
// ...
h(); // the value of a might change
// ...
}
void g(Obj a)
{
// ...
h(); // the value of a is unlikely to change
// ...
}
不幸的是,这个例子不是铸铁。可以编写一个类,例如,在其构造函数中向自身添加指向全局状态对象的指针,这样即使是类型的本地对象也可能被全局函数调用更改。尽管如此,仍然有更多机会对本地对象进行有效优化,因为它们不能通过传入的引用或其他预先存在的对象直接别名。
应该在实际需要引用语义的地方选择通过const
引用传递参数,或者仅在复制参数的费用超过潜在别名的成本时才选择性能改进。
答案 1 :(得分:22)
按值传递参数并因此复制它们可能很昂贵 - const引用避免了这个昂贵的步骤,同时仍然向调用者承诺不会更改对象。
通常基本类型(int
,double
,...)通过值传递,而类类型通过const引用传递。
然而,exceptions可以为类类型传递值有用。
答案 2 :(得分:4)
在某些情况下,制作对象的副本可能会极大地影响性能。考虑一个函数,该参数将为std::vector<long>
,并且您希望传递具有100万个元素的向量。在这种情况下,您将要使用const引用而不是传递值。在this SO question 中,您可以找到针对您问题的简单通则。
答案 3 :(得分:2)
有时,制作一个对象的副本可能很昂贵,因此传递const引用将避免必须制作该副本。否则,我会说你应该简单地按值传递,如果这是语义上的要求。
答案 4 :(得分:2)
按值传递参数会导致传递给函数的对象副本的开销。
也许对象不可复制,您的选择有限。
答案 5 :(得分:2)
由于您将获得性能优势。假设你有一个大对象(就字节大小而言)。现在,如果您通过值将此对象传递给函数,则需要为此创建不必要的副本,但是您可以通过将const引用传递给该对象本身而不创建副本来获得相同的效果。由于引用通常存储为引擎盖下的指针,因此传递引用的成本仅为sizeof(pointer)
。
答案 6 :(得分:2)
数组不能通过值传递,因此这是使用const指针的好时机。
答案 7 :(得分:1)
避免制作不必要的副本,从而提高效果。