C ++ dependency on argument for const reference doesn't change

Pay attention to the following code:

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

Compiled with g ++ 4.6 with -O3, I see that the compiled one re-reads the value "a" between function calls. Changing the definition to "const int", the compiler does not do this, but instead simply loads the immediate value "12" into edi. The same is true if a is not const, but I am changing the signature of func1 to accept by value.

Although this is not an error in code generation, it is still a weird behavior. Being that func1 made a commitment not to change a, why does the compiler code change depending on whether const is const or not?

Change Some skeptics claim that I may be reading the code incorrectly. The above code gives the following with -S compilation:

 _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 

Changing a to const produces:

 _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 
+8
c ++ gcc
source share
2 answers

In C ++, const is actually just a logical constant, not a physical constant. func1 can execute const_cast and change i . const is like gun safety - you can still shoot in the leg, but not by accident.

As TC and juanchopanza pointed out in the comments, discarding the const ness of the object and changing its UB. A quote from the "Notes" here :

Even though const_cast can remove constant or volatility from any pointer or reference using a result pointer or a link to write to an object, a declared const or access to the declared volatile object causes undefined behavior.

+6
source share

Summing up the answers, I think this explains it best:

Legally refer to a constant reference to a non-constant variable, and then discard the constant. Therefore, in the first case, the compiler cannot assume that func1 will not change a .

This is undefined, which happens if you drop the constant to the declared variable const. In the second case, the compiler may assume that func1 will not drop the constant. If func1 discards a constant, func2 will get the "wrong" value, but this is just one of the consequences of undefined behavior.

+3
source share

All Articles