C ++依赖于const引用的参数没有改变

时间:2014-07-30 05:39:04

标签: c++ gcc gcc4.6

请考虑以下代码:

void func1(const int &i);
void func2(int i);

void f()
{
  int a=12;
  func1(a);
  func2(a);
}

使用带有-O3的g ++ 4.6编译,我可以看到编译后重新读取" a"的值。函数调用之间。将一个定义更改为" const int",编译器不会这样做,而是简单地加载立即值" 12"进入edi。如果a不是const,则同样如此,但我将func1的签名更改为按值接受。

虽然不是代码生成中的错误,但这仍然是奇怪的行为。因为func1承诺不改变a,为什么编译器的代码会根据a是否为const而改变?

编辑:一些怀疑论者声称我可能会错误地阅读代码。上面的代码使用-S编译产生以下内容:

_Z1fv:
.LFB0:
        .cfi_startproc
        subq    $24, %rsp
        .cfi_def_cfa_offset 32
        leaq    12(%rsp), %rdi
        movl    $12, 12(%rsp)                                                          
        call    _Z5func1RKi
        movl    12(%rsp), %edi     <-- Rereading a
        call    _Z5func2i
        addq    $24, %rsp
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc                                                           

将a更改为const会产生:

_Z1fv:
.LFB0:
        .cfi_startproc
        subq    $24, %rsp
        .cfi_def_cfa_offset 32
        leaq    12(%rsp), %rdi
        movl    $12, 12(%rsp)
        call    _Z5func1RKi
        movl    $12, %edi          <-- Use immediate value
        call    _Z5func2i
        addq    $24, %rsp
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc

2 个答案:

答案 0 :(得分:6)

在C ++中,const实际上只是逻辑常量,而不是物理常量。 func1可以执行const_cast并修改iconst就像枪的安全 - 你仍然可以用脚射击自己,但不是偶然的。

作为T.C.和juanchopanza在评论中指出,抛弃对象的const并修改它是UB。引用&#34; Notes&#34; here

  

尽管const_cast可以从任何指针或引用中删除constness或volatile,但是使用结果指针或引用来写入声明为const的对象或访问声明为volatile的对象会调用未定义的行为。

答案 1 :(得分:3)

总结答案,我认为这最能解释:

对非const变量采用const引用,然后抛弃constness是合法的。因此,第一种情况下的编译器不能假设func1不会更改a

未定义如果将constness转换为声明为const的变量会发生什么。第二种情况下的编译器可能假设func1不会抛弃constness。如果func1抛弃了常量,func2将收到&#34;错误&#34;价值,但这只是未定义行为的一个后果。