在 C# 或 php 或其他语言中,将值传递给函数有 2 种方式,按值传递和通过引用传递。
按值传递参数使值复制到函数中,因此这需要额外的内存空间,尽管内存空间在函数外运行后会被回收。
但是通过引用传递参数不需要复制一个值,它节省了内存。从这个角度来说,我们是否可以说使用“引用传递”总是比“值传递”更好?
在 C# 或 php 或其他语言中,将值传递给函数有 2 种方式,按值传递和通过引用传递。
按值传递参数使值复制到函数中,因此这需要额外的内存空间,尽管内存空间在函数外运行后会被回收。
但是通过引用传递参数不需要复制一个值,它节省了内存。从这个角度来说,我们是否可以说使用“引用传递”总是比“值传递”更好?
不。
在很多情况下,您都希望按值传递。
一个例子可能是当您同时需要const Type&
和Type&&
重载时。按值传递只处理这两种情况,而无需复制任何代码:
void function(Object o) { do_something_with(std::move(o)); }
相对于:
void function(Object&& o) { do_something_with(std::move(o)); }
void function(const Object& o) { do_something_with(Object(o)); }
当然,这个主题还有更多内容,但既然你只是在问“它总是更好吗? ”我觉得一个反驳的例子就足够了。;)
编辑:这个问题最初被标记为c++ ,因此我的回答非常具体。
另一个与语言无关的示例是当您因为不想修改原始对象而需要复制参数时:
void function(int& val) { int v2 = val; modify(v2); use(v2); }
// vs
void function(int val) { modify(val); use(val); }
你明白了……
按引用传递和按值传递在语义上是不同的,有时一种是正确的方法,有时另一种是正确的方法。在许多情况下,手头的任务已经规定了需要哪种方法,并且在只支持一个选项的上下文中,您通常需要手动解决它(例如,如果您需要 Java 中的副本,则需要clone()
该对象)。
在泛型函数的上下文中,答案与您提出的偏好相反:按值传递推导类型的参数!原因是您可以使用类似std::ref()
获取引用语义的方法,但如果函数使用引用语义,则无法获取值语义。
通过引用传递需要复制对对象的引用。如果该参考在成本上与对象本身相当,那么收益是虚幻的。此外,有时您需要对象的副本,而按值传递可以为您提供一个。
此外,问题的推理存在一个关键错误。如果按值传递,并且不需要复制值,则不需要实际复制值。大多数语言都有一个“as-if”规则,该规则规定程序只需要像编译器按照您的要求进行操作一样。因此,如果可以避免复制,编译器可以自由地避免它。如果无法避免副本,那么您需要副本。