C++ 引用和数组索引之间有什么区别吗?
假设您希望访问数组中的结构,并修改几个字段。您可以直接这样做,如:C++ 引用和数组索引之间有什么区别吗?,c++,compiler-construction,C++,Compiler Construction,假设您希望访问数组中的结构,并修改几个字段。您可以直接这样做,如: units[unitIndex].field1 = value1; units[unitIndex].field2 = value2; units[unitIndex].field3 = value3; ... 或者,您可以提取对结构的引用,然后从中修改它们: unitStruct& unit = units[unitIndex]; unit.field1 = value1; unit.field2 = value2;
units[unitIndex].field1 = value1;
units[unitIndex].field2 = value2;
units[unitIndex].field3 = value3;
...
或者,您可以提取对结构的引用,然后从中修改它们:
unitStruct& unit = units[unitIndex];
unit.field1 = value1;
unit.field2 = value2;
unit.field3 = value3;
...
我一直认为第二种方法“更好”,它不必每次都索引到数组中来重新找到结构
但是当我停下来思考时,我意识到编译器很可能将数组索引作为指针来实现。引用也可能被实现为指针。也许他们内部也在做同样的事情
所以我想知道的是,从编译器的角度来看,在生成的代码方面,这两种方法之间有什么真正的区别吗?编译器是否会为其中一种方法生成任何额外的代码,或者它们本质上是两种获得完全相同结果的方法?在启用优化的情况下编译时,编译器将以任何一种方式生成相同的代码,您应该使用任何使代码对您和代码维护人员更具可读性的样式 比如说
#include <cstddef>
#include <vector>
struct unitStruct {
int field1;
int field2;
int field3;
};
void noref( std::vector<unitStruct> & units, size_t unitIndex, int value1, int value2, int value3 )
{
units[unitIndex].field1 = value1;
units[unitIndex].field2 = value2;
units[unitIndex].field3 = value3;
}
void ref( std::vector<unitStruct> & units, size_t unitIndex, int value1, int value2, int value3 )
{
unitStruct& unit = units[unitIndex];
unit.field1 = value1;
unit.field2 = value2;
unit.field3 = value3;
}
生成了相同的代码-前三条指令以不同的顺序出现,但仅此而已:
0000000000000000 <_Z5norefRSt6vectorI10unitStructSaIS0_EEmiii>:
0: 48 8d 04 76 lea (%rsi,%rsi,2),%rax
4: 48 8b 37 mov (%rdi),%rsi
7: 48 8d 04 86 lea (%rsi,%rax,4),%rax
b: 89 10 mov %edx,(%rax)
d: 89 48 04 mov %ecx,0x4(%rax)
10: 44 89 40 08 mov %r8d,0x8(%rax)
14: c3 retq
0000000000000020 <_Z3refRSt6vectorI10unitStructSaIS0_EEmiii>:
20: 4c 8b 0f mov (%rdi),%r9
23: 48 8d 04 76 lea (%rsi,%rsi,2),%rax
27: 49 8d 04 81 lea (%r9,%rax,4),%rax
2b: 89 10 mov %edx,(%rax)
2d: 89 48 04 mov %ecx,0x4(%rax)
30: 44 89 40 08 mov %r8d,0x8(%rax)
34: c3 retq
0000000000000000:
0:48 8d 04 76 lea(%rsi,%rsi,2),%rax
4:48 8b 37 mov(%rdi),%rsi
7:48 8d 04 86 lea(%rsi,%rax,4),%rax
b:89 10 mov%edx,(%rax)
d:89 48 04 mov%ecx,0x4(%rax)
10:44894008 mov%r8d,0x8(%rax)
14:c3 retq
0000000000000020 :
20:4c 8b 0f mov(%rdi),%r9
23:48 8d 04 76 lea(%rsi,%rsi,2),%rax
27:49 8d 04 81 lea(%r9,%rax,4),%rax
2b:89 10 mov%edx,(%rax)
2d:89 48 04 mov%ecx,0x4(%rax)
30:44894008 mov%r8d,0x8(%rax)
34:c3 retq
我几乎不相信有什么区别。
units[unitIndex]
将为您提供一个unitStruct&
我认为唯一的区别是当有人阅读代码时。在调试模式下,是的,编译器可以生成不同的代码。对于units[unitIndex],它可以计算每行的units+unitIndex指针。如果使用引用,偏移量将计算一次,并存储在堆栈上 在优化的构建中,在这两种情况下,编译器可能只进行一次计算,并将计算出的偏移量保存在寄存器中 重要的是,它更具可读性和可维护性。当你对一件事进行优化时,你对另一件事感到悲观。在几乎所有情况下,您都应该优化可读性和可维护性
[ETA]如果您真的对差异感到好奇,可以让编译器将生成的程序集写入文件。有关如何执行此操作,请参阅编译器的帮助。您应该注意,优化是通过-O3启用的。
0000000000000000 <_Z5norefRSt6vectorI10unitStructSaIS0_EEmiii>:
0: 48 8d 04 76 lea (%rsi,%rsi,2),%rax
4: 48 8b 37 mov (%rdi),%rsi
7: 48 8d 04 86 lea (%rsi,%rax,4),%rax
b: 89 10 mov %edx,(%rax)
d: 89 48 04 mov %ecx,0x4(%rax)
10: 44 89 40 08 mov %r8d,0x8(%rax)
14: c3 retq
0000000000000020 <_Z3refRSt6vectorI10unitStructSaIS0_EEmiii>:
20: 4c 8b 0f mov (%rdi),%r9
23: 48 8d 04 76 lea (%rsi,%rsi,2),%rax
27: 49 8d 04 81 lea (%r9,%rax,4),%rax
2b: 89 10 mov %edx,(%rax)
2d: 89 48 04 mov %ecx,0x4(%rax)
30: 44 89 40 08 mov %r8d,0x8(%rax)
34: c3 retq