引用和数组索引之间有什么区别吗?

时间:2014-04-10 13:09:27

标签: 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;
unit.field3 = value3;
...

我总是假设第二种方法“更好”,每次重新找到结构时都不必索引数组。

但是当我停下来思考它时,我意识到编译器可能将数组索引实现为指针。并且该引用也可能被实现为指针。也许他们在内部做同样的事情?

所以我想知道的是,从生成代码的编译器角度来看,这两种方法之间是否有任何真正的区别?编译器是否为这些方法之一生成了任何额外的代码,或者它们实际上是两种获得完全相同结果的方法?

3 个答案:

答案 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;。

我认为当有人阅读代码时,唯一的区别就在于此。