函数参数作为常量引用

14
发送一个参数作为const &而不是按值发送,如果它不会被更改且不会进行复制,是否有任何原因不这样做? 我的理解是,按值传递的const与没有const(并且不会相互重载)相同,因此仍将被复制。
我知道对于大对象来说,最好通过const &发送,但我不知道这条线在哪里。或者,即使是小参数也应该按值发送如果它们不会被更改或复制。
注意::我尝试搜索此内容,但该主题相当模糊,因此我没有找到任何好的答案,如果已经回答了这个问题,我很抱歉(发现许多关于何时使用const关于何时使用const &的问题,但没有关于明显较大的对象的值与const &之间优劣的问题)。

2
你可能会对这篇文章感兴趣:http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ - lccarrasco
正是我正在寻找的类型,谢谢!这些关键词太笼统了,让我很难搜索。 - Stu
@lccarrasco:Dave Abrahams正在谈论从函数内部按值返回对象。问题是关于函数的输入参数。在这种情况下,OP应该通过const引用传递除本地类型以外的对象。 - Praetorian
从概念上讲,引用是一个别名。它不是指针,尽管在某些情况下编译器别无选择,只能将其秘密实现为指针。因此,有时通过值传递基本类型可能会更快。但在许多情况下,我看到编译器使用引用做出真正惊人的事情,完全消除了它们,基本上就像您在其他函数作用域中使用原始变量一样。 - Damon
@iccarrasco的链接确实是关于返回值的,但这也是一个重要的考虑因素。特别是如果你想知道在函数调用期间参数(和返回值!)如何传递的详细信息,那么了解RVO是非常值得的...别忘了使用优化编译! - Kerrek SB
@Praetorian:啊,是的。不过这篇文章还是很有趣的。 - Stu
3个回答

24

将只读参数作为const引用传递通常是没有问题的,对于任何重量级的类来说,这肯定是最有效的方法。

然而,对于原始数据类型,您可能考虑通过复制进行传递,因为在这种情况下,创建引用实际上可能比仅仅复制更加耗费时间(例如,复制可以适合一个寄存器,而引用可能是通过指针实现的等等)。

此外,您可能可以通过值传递std::shared_ptr和迭代器,它们就是为此而设计的。

至于通过const-value传递,这是一个实现细节。像这样使用:

// Declaration:
int foo(int n, double d); // No "const"! Constness is not part of the interface.

// Definition
int foo(int n, const double d) // implementation detail
{
  while (n--) { if (d > n) return n; }
}
在实现中,你可以选择直接使用参数变量并修改它们(如 n),也可以选择将它们视为只读的(如 d),并适当声明参数。

3
我没有考虑到原始类型的指针复制也可能同样昂贵,甚至更糟,谢谢提醒。 - Stu
8
值得指出的是,如果您跨线程边界通过引用传递引用计数句柄(例如 shared_ptr),那么将无法安全地递减引用计数 -- 在这种情况下,必须通过值传递。 - spraff

14

通常情况下,你应该通过(非const)值传递基本数据类型,例如指针、intboolfloatdouble,通过(const)引用传递对象类型,例如std::stringstd::vector和自定义类。但是有一些特殊的轻量级类(例如智能指针)是设计成通过值传递的。

将值作为const值传递,例如void foo(const double bar),没有意义--为什么不允许foo修改它的副本bar?在这里声明参数为const没有任何用处。

将基本数据类型传递给函数也很少见。在幕后,当一个参数通过引用传递时,一个指针通过值传递。复制指针通常与复制基本数据类型(例如int)同样昂贵,而const int&类型的参数看起来对大多数C++程序员来说很奇怪。


4
有一些人(我不是其中之一)实际上更喜欢使用“const double bar”。他们说这可以防止在函数中重写参数值而导致的错误。 - Fred Foo
仅仅是为了补充@larsmans的评论,使用const double bar可以防止你意外地执行if (bar = 5)而不是==。但这是以限制你对bar所能做的事情为代价的。你的算法可能会因某种原因要求就地修改bar。我想这只是灵活性与安全性之间的权衡。这取决于你有多少信任下一个程序员! - Cam Jackson

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接