假设您要访问数组中的结构,并修改多个字段。你可以直接这样做:
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;
...
我总是假设第二种方法“更好”,每次重新找到结构时都不必索引数组。
但是当我停下来思考它时,我意识到编译器可能将数组索引实现为指针。并且该引用也可能被实现为指针。也许他们在内部做同样的事情?
所以我想知道的是,从生成代码的编译器角度来看,这两种方法之间是否有任何真正的区别?编译器是否为这些方法之一生成了任何额外的代码,或者它们实际上是两种获得完全相同结果的方法?
答案 0 :(得分:2)
当启用优化编译时,编译器将生成相同的代码,您应该使用任何样式使代码对您和维护代码的人更具可读性。
例如
#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;
}
使用gcc编译并启用优化 -O3
g++ -O3 -c struct.cpp -o struct.o
objdump -D struct.o|less
生成相同的代码 - 前三个指令以不同的顺序出现,但是它是:
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
答案 1 :(得分:1)
在调试模式下,是的,编译器可以生成不同的代码。对于单位[unitIndex],它可以计算每行的单位+ unitIndex指针。如果使用参考,则偏移量将计算一次,并存储在堆栈中。
在优化构建中,在两种情况下,编译器可能会执行一次计算并将计算出的偏移量保存在寄存器中。
重要的是,它更易读,更易于维护。当你优化一件事时,你会对其他事情感到悲观。几乎在所有情况下,您都应该优化可读性和可维护性。
[ETA]如果您对这种差异非常好奇,可以让编译器将生成的程序集写入文件。有关如何执行此操作,请参阅编译器的帮助。
答案 2 :(得分:0)
我几乎不相信有任何区别。
units[unitIndex]
将为您提供unitStruct&amp;。
我认为当有人阅读代码时,唯一的区别就在于此。