我对按值调用和按引用调用 const 之间的区别有点困惑。有人可以向我解释一下吗。例如,它们是否都可以防止更改调用者参数,它们是否适用于所有对象大小,是否复制参数而一个不复制参数,以及在复制时使用更多内存?
5 回答
它们是否都可以防止更改调用者参数
按值传递会创建调用者提供的参数的副本,因此无论函数做什么,它都会在单独的对象上执行。这意味着永远不会触及原始对象,因此在这种情况下,答案是“是”。
const
另一方面,通过引用传递,让函数引用调用者提供的同一个对象,但它不会让该函数修改它......除非(正如 Luchian Grigore 在评论中正确指出的那样)函数的实现者使用从引用const_cast<>
中丢弃const
-ness,只有在知道绑定到引用的对象未声明为const
类型时才能安全地完成此操作(否则,您将获得未定义的行为)。
由于考虑到您的问题,这似乎不是最有可能的情况,并且考虑到通常接受对 的引用const
表示不会触及该论点的承诺,那么答案是,只要我们假设这个承诺是满足,通过引用传递const
不会改变调用者提供的参数。所以答案再次是“是”——我上面提到的一点警告。
它们对所有物体大小都快吗
不,尽管您应该首先定义“快速”。如果要传递的对象的类型复制起来(或移动,如果执行的是移动而不是复制)代价高昂,那么按值传递可能会很慢。无论您传递的值的类型是什么,通过引用传递总是会花费相同的成本(地址的大小)。
请注意,在某些体系结构和某些数据类型(如char
)上,按值传递可能比按引用传递更快,而对于足够大的 UDT,情况通常相反。
制作副本时哪个使用更多内存?
由于其中只有一个导致复制,因此问题有一个明显的答案。
按值调用将复制它确实保护调用者参数的对象的所有元素,因为如果您要更改某些内容,它只是您正在更改的副本。
通过 const 引用调用不会复制元素,但由于“const”,它将保护调用者的参数。
你 const 参考。
主要区别在于通过const
引用(或非常量)传递不会复制参数。(副本实际上会受到复制省略,但理论上它是在您通过值传递时传递给函数的副本)
在某些情况下,按值传递同样快,甚至更快(通常当对象最多为寄存器大小时)。您通常会通过值传递基本类型,并通过引用传递类类型。
通过const
引用传递时,您仍然可以通过将 const 强制转换(通过const_cast
)来修改原始值,但如果原始值为 .,则会导致未定义的行为const
。
我想你的意思是:
void Fn1(MyType x);
和
void Fn2(const MyType& x);
在前一种情况下,始终会创建对象的副本,这会使其速度变慢,尤其是在类型具有非平凡构造函数的情况下。原始对象将不受函数内对副本所做的任何更改的影响,但副本本身可以更改。
后一个示例不会创建副本,并且通常会更快。在函数内部,只能在参数上调用 const 函数(除非您使用诸如丢弃 const 之类的肮脏技巧),从而保证不会修改对象。
重要提示:本讨论不涉及具有特殊语义的类型,例如智能指针。在这种情况下,按值调用仍然允许您更改逻辑上相同的对象,即不是智能 ptr 实例本身,而是它指向的对象。
因此,这里是您的问题的答案:
- 它们是否都可以防止更改调用者参数:是的,原始对象将保持不变(不包括技巧)
- 它们是否对所有对象大小都快:它们不是同样快 - 通过引用调用通常更快,除了一些速度或多或少相同甚至可能稍微快一点的原始类型,具体取决于编译器优化。
- 要么复制参数,而不要复制参数:按值调用创建副本,按引用调用不会
- 制作副本时哪个使用更多内存?引用调用不会创建副本,因此答案很明确
另一点值得一提的是,引用调用函数被转换为内联函数。