也许这是编译器特定的东西。如果是这样,gcc(g ++)怎么样?如果您使用这样的变量引用/别名:
int x = 5;
int& y = x;
y += 10;
它实际上是否需要比我们不使用引用更多的周期。
int x = 5;
x += 10;
换句话说,机器代码是否发生变化,或者“别名”是否仅在编译器级别发生?
这似乎是一个愚蠢的问题,但我很好奇。特别是在可能暂时重命名某些成员变量以便数学代码更易于阅读的情况下。当然,我们并没有在这里谈论瓶颈......但这是我正在做的事情,所以我只是想知道是否存在任何“实际”差异......或者它是否仅仅是装饰性的。
答案 0 :(得分:9)
它可以被视为别名,但不是效率方面。在引擎盖下,引用是一个具有更好语法和更高安全保证的指针。因此,您有一个“取消引用”操作运行时惩罚。除非编译器优化它,但我通常不会指望它。
如果编译器是否会对其进行优化,那么除了查看生成的程序集之外别无他法。
答案 1 :(得分:4)
唯一可以确定的方法是编译它并检查编译器的输出。通常,引用的开销类似于指针的开销,因为指针通常是如何实现引用的。但是,考虑到你正在展示的简单案例,我相信参考文献会被优化掉。
答案 2 :(得分:4)
确实,在大多数情况下,引用实现了“别名”的概念,这是它们所绑定的对象的替代名称。
但是,一般情况下,引用是通过指针实现的。然而,一个好的编译器只会在实际绑定在运行时确定的情况下使用实际指针来实现引用。如果在编译时已知绑定(并且类型匹配),则编译器通常会将引用实现为同一对象的备用名称,在这种情况下,通过引用访问对象不会有性能损失(与访问相比)它通过它的原始名称。)
您的示例就是其中之一,您应该预期参考不会造成性能损失。
答案 3 :(得分:4)
这两个函数都编译为g++
中完全相同的代码,即使只使用-O1
。 (我添加了return
语句,以确保计算没有完全消除。)
没有指针,只有参考。在这个微不足道的例子中,没有性能差异。但是,并不能保证所有参考用途的情况总是如此(没有性能差异)。
int f()
{
int x = 5;
x += 10;
return x;
}
int f()
{
int x = 5;
int & y = x;
y += 10;
return y;
}
汇编程序:
movl $15, %eax
ret
答案 4 :(得分:3)
我在Gnu / Linux上比较了2个程序。下面仅显示GCC输出,但是clang结果得出相同的结论。
GCC版本: 4.9.2
Clang版本: 3.4.2
<强> 1.cpp 强>
#include <stdio.h>
int main()
{
int x = 3;
printf("%d\n", x);
return 0;
}
<强> 2.cpp 强>
#include <stdio.h>
int main()
{
int x = 3;
int & y = x;
printf("%d\n", y);
return 0;
}
尝试1:无优化
gcc -S --std=c++11 1.cpp
gcc -S --std=c++11 2.cpp
1.cpp的组装时间较短。
尝试2:优化
gcc -S -O2 --std=c++11 1.cpp
gcc -S -O2 --std=c++11 2.cpp
最终的装配完全相同。
1.cpp,无优化
.file "1.cpp"
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $3, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.9.2-10) 4.9.2"
.section .note.GNU-stack,"",@progbits
2.cpp,无优化
.file "2.cpp"
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $3, -12(%rbp)
leaq -12(%rbp), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movl (%rax), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.9.2-10) 4.9.2"
.section .note.GNU-stack,"",@progbits
1.cpp,优化
.file "1.cpp"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d\n"
.section .text.unlikely,"ax",@progbits
.LCOLDB1:
.section .text.startup,"ax",@progbits
.LHOTB1:
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB12:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $3, %esi
movl $.LC0, %edi
xorl %eax, %eax
call printf
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE12:
.size main, .-main
.section .text.unlikely
.LCOLDE1:
.section .text.startup
.LHOTE1:
.ident "GCC: (Debian 4.9.2-10) 4.9.2"
.section .note.GNU-stack,"",@progbits
2.cpp,优化
.file "1.cpp"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d\n"
.section .text.unlikely,"ax",@progbits
.LCOLDB1:
.section .text.startup,"ax",@progbits
.LHOTB1:
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB12:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $3, %esi
movl $.LC0, %edi
xorl %eax, %eax
call printf
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE12:
.size main, .-main
.section .text.unlikely
.LCOLDE1:
.section .text.startup
.LHOTE1:
.ident "GCC: (Debian 4.9.2-10) 4.9.2"
.section .note.GNU-stack,"",@progbits
优化GCC输出时没有运行时成本。与clang相同(使用3.4.2版测试):当启用优化时,生成的汇编代码在两个程序中都是相同的。
答案 5 :(得分:0)
是的,取消引用引用后面的指针会产生额外的运行时成本,但可能无关紧要。以最清晰的方式编写代码,最清晰地表达您所针对的语义,然后在性能成为问题的情况下在分析器中运行(瓶颈很少是您猜测的)。如果您使用的是MacOS,Shark非常棒。