Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ reliance on argument to const reference not changing

Tags:

c++

gcc

gcc4.6

Please consider 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 can see that the compiled re-reads the value of "a" between the function calls. Changing a's definition to "const int", the compiler doesn't do that, and instead simply loads immediate value "12" into edi. The same is true if a is not const, but I change func1's signature to accept by value.

While not a bug in the code generation, this is still weird behavior. Being as it is that func1 made a commitment not to change a, why should the compiler's code change based on whether a is const or not?

Edit: Some skeptics claim that I might be reading the code wrong. The above code produces 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
like image 809
Shachar Shemesh Avatar asked Jul 30 '14 05:07

Shachar Shemesh


People also ask

Why can't the function called by reference-to-const be stored in the argument?

When passing by reference-to-const, the called function can't store into the actual argument because it's const . Last month, I explored the similarities between pointer and reference initialization.

Is it illegal to use constant reference parameter in C++?

No, your code is legal and will produce the same results on all conforming compilers. A constant reference parameter does not make the thing that it refers to const if it was not const to begin with. All it does it stop you from using the reference to modify the object.

How bad is it to write a const reference in C++?

C++ programmers are accustomed to this, i.e. as long as a programmer doesn't hate C++, the overhead of writing or reading const-reference in source code isn't horrible.

Is it possible to reassign a const reference to a pointer?

Thus we get the output we expected to see. Const Reference to a pointer is a non-modifiable value that’s used same as a const pointer. Here we get a compile-time error as it is a const reference to a pointer thus we are not allowed to reassign it.


2 Answers

In C++, const is really just logical constness and not physical constness. func1 can do a const_cast and modify i. const is like the safety of a gun - you can still shoot yourself in the foot, but not by accident.

As T.C. and juanchopanza have pointed out in the comments, casting away the constness of an object and modifying it is UB. Quoting from "Notes" here :

Even though const_cast may remove constness or volatility from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const or to access an object that was declared volatile invokes undefined behavior.

like image 122
Pradhan Avatar answered Oct 21 '22 11:10

Pradhan


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

It is legal to take a const reference to a non-const variable, and then cast away the constness. Therefore, the compiler in the first case cannot assume that func1 will not change a.

It is undefined what happens if you cast away the constness to a variable declared const. The compiler in the second case may assume that func1 will not cast away the constness. If func1 does cast away the constness, func2 will receive the "wrong" value, but that's just one consequence of undefined behaviour.

like image 24
Shachar Shemesh Avatar answered Oct 21 '22 10:10

Shachar Shemesh