主流编译器是否将引用传递基本类型转换为复制传递?
通过引用传递对象是向其传递地址的一种更简单、更快速且更安全的方法。 但对于大多数编译器来说,都是一样的:引用实际上是指针。
现在像 int
这样的基本类型呢?将地址传递给 int
并在函数内使用它会比通过复制传递它慢,因为在使用之前需要取消引用指针。
现代编译器如何处理这个?
int foo(const int & i)
{
cout << i; // Do whatever read-only with i.
}
我可以相信他们会把这个编译成这个吗?
int foo(const int i)
{
cout << i;
}
顺便说一句,在某些情况下,同时传递 i
和 &i
甚至可能更快,然后使用 i
进行读取,然后 < code>*i 用于书写。
int foo(const int i, int * ptr_i)
{
cout << i; // no dereferencement, therefore faster (?)
// many more read-only operations with i.
*ptr_i = 123;
}
Passing an object by reference is an easier, faster and safer way to pass an address to it.
But for most compilers, it's all the same: references are really pointers.
Now what about basic types like int
? Passing an address to an int
and using it inside a function would be slower than passing it by copy, because the pointer needs to be dereferenced before use.
How do modern compiler handle, this?
int foo(const int & i)
{
cout << i; // Do whatever read-only with i.
}
May I trust them to compile this into this?
int foo(const int i)
{
cout << i;
}
By the way, in some cases it could even be faster to pass both i
and &i
, then use i
for reading, and *i
for writing.
int foo(const int i, int * ptr_i)
{
cout << i; // no dereferencement, therefore faster (?)
// many more read-only operations with i.
*ptr_i = 123;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
gcc 似乎没有使用 -O3 (gcc 版本 4.7.2)进行此优化。使用 Gabriel 的代码,请注意 ok2 如何在索引到 vars 之前加载取消引用的地址,而 ok1 则不然。
好的1:
ok2:
gcc does not appear to do this optimization with -O3 (gcc version 4.7.2). Using Gabriel's code, note how ok2 loads a dereferenced address before indexing into vars while ok1 does not.
ok1:
ok2:
我可以相信他们会把这个编译成这个吗?
是的,你可以。[这里的“是”意味着不同,请阅读编辑部分,其中澄清了]
告诉编译器
i
是对类型常量整数的引用。编译器可以执行优化,但只能按照假设规则执行优化。因此,您可以放心,对于您的程序,上述行为将与(将遵守
const
限定符)一样好:假设规则:
对于 Standerdese 粉丝:
C++03 1.9“程序执行:
脚注说:
编辑:
由于答案有些混乱,让我澄清一下:
优化不能在编译器上强制执行。因此编译器如何解释它取决于编译器。重要的是程序的可观察行为不会改变。
May I trust them to compile this into this?
Yes You can.[The Yes here means differently, Please read Edit section, Which clarify's]
Tells the compiler that
i
is an reference to type constant integer.The compiler may perform optimizations but they are only allowed to perform optimizations following the As-If Rule. So you can be assured that for your program the behavior of the above will be as good as(the
const
qualifier will be respected):As-If Rule:
For Standerdese fans:
C++03 1.9 "Program execution:
And the Foot-Note says:
EDIT:
Since there is some confusion about the answer let me clarify:
Optimizations cannot be enforced on the compiler.So How compiler interprets it depends on the compiler.The important thing is the observable behavior of the program will not change.
它不应该将其编译为该内容,因为它可能不正确。考虑:
与
编译器如何知道这不会发生?它必须以某种方式能够分析不可能访问该变量来更改它,例如(1)有人拥有指针,(2)它可能是全局变量,(3)来自另一个线程。考虑到 C 的不安全性质,使用指针算术等,甚至保证函数无法获取指向变量的指针也可能是不可能的。
It shouldn't compile it into that because it might not be correct. Consider:
versus
How does the compiler know that this won't happen? It would have to somehow be able to analyze that it is impossible to access that variable to change it, e.g. (1) someone having a pointer, (2) it might be a global variable, (3) from another thread. Given the unsafe nature of C, with pointer arithmetic and all, even guaranteeing that the function won't be able to get a pointer to the variable might be impossible.
至少在我测试过的简单情况下,Visual Studio 2010 (Express) 确实如此。有人要测试gcc吗?
我已经测试了以下内容:
1。仅传递
i
:ASM:
嗯,ASM 是相同的,毫无疑问执行了优化。
2.传递
i
和&i
:让我们在这里考虑 @newacct 的 anser。
ASM:
在
ok1
中,我看不到它将2写入pi
。可能它明白无论如何该内存位置都会被函数的结果覆盖,所以写入是没有用的。使用
ok2
,编译器就像我预期的那样聪明。它知道i
和pi
指向同一个地方,因此它直接使用硬编码的2
。注释:
ok1
,一次仅取消注释ok2
。同时编译这两个函数会导致两个函数之间的优化更加复杂,最终导致所有内联和混合。vars
中添加了一个查找,因为对sqrtl< 的简单调用/code> 被简化为基本的类似 ADD 和 MUL 的操作,无需实际调用
Visual Studio 2010 (Express) does, in the simple cases I've tested at least. Anyone to test gcc?
I've tested the following:
1. Passing only
i
:The ASM:
Well, the ASMs are identical, no doubt the optimization was performed.
2. Passing
i
and&i
:Let's consider @newacct 's anser here.
The ASM:
In
ok1
I can't see it writing 2 intopi
. Probably it understands that the memory location will be overwritten by the result of the function anyway, so the writing is useless.With
ok2
, the compiler is as smart-ass as I expected. It understands thati
andpi
point to the same place, so it uses a hardcoded2
directly.Notes:
ok1
, once uncommenting onlyok2
. Compiling both at the same time leads to more complex optimizations between the two functions, which end up all inlined and mixed upvars
because simple calls tosqrtl
were simplified into basic ADD- and MUL-like operations without the actual call