30

After coming across something similar in a co-worker's code, I'm having trouble understanding why/how this code executes without compiler warnings or errors.

#include <iostream> int main (void) { unsigned int u = 42; const int& s = u; std::cout << "u=" << u << " s=" << s << "\n"; u = 6 * 9; std::cout << "u=" << u << " s=" << s << "\n"; } 

Output:

u=42 s=42 u=54 s=42 

First, I expect the compiler to issue some kind of diagnostic when I mix signed/unsigned integers like this. Certainly it does if I attempt to compare with <. That's one thing that confuses me.

Second, I'm not sure how the second line of output is generated. I expected the value of s to be 54. How does this work? Is the compiler creating an anonymous, automatic signed integer variable, assigning the value of u, and pointing the reference s at that value? Or is it doing something else, like changing s from a reference to a plain integer variable?

8
  • 1
    const int& s = u; first creates a new temporary int which is then assigned to the const int&. That's why it won't work with a non-const reference Commented Jan 14, 2022 at 15:22
  • 9
    This is an interesting C++ gotcha that I've never seen before. Commented Jan 14, 2022 at 15:24
  • 2
    It may help understand the behavior to realize that in C++ a const reference can, in some cases, extend the lifetime of a temporary that is assigned to it. Basically, if the temporary was created during the initialization of the reference, in most cases it will extend the lifetime of the temporary to that of the reference. A function local variable is one of those cases. Commented Jan 14, 2022 at 15:26
  • 2
    See here for more about the lifetime extension. "The lifetime of a temporary object may be extended by binding to a const lvalue reference [or to an rvalue reference (since C++11)], see reference initialization for details." Commented Jan 14, 2022 at 15:27
  • 1
    @Eljay: this special case is not UB: eel.is/c++draft/basic.lval#11.2 Commented Jan 25, 2022 at 10:41

1 Answer 1

25

References can't bind to objects with different type directly. Given const int& s = u;, u is implicitly converted to int firstly, which is a temporary, a brand-new object and then s binds to the temporary int. (Lvalue-references to const (and rvalue-references) could bind to temporaries.) The lifetime of the temporary is prolonged to the lifetime of s, i.e. it'll be destroyed when get out of main.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the explanation. This is completely counterintuitive to me. No wonder why people dread C++!
Interesting stuff, this means that printf("%p %p", &u, &s); will print different values, as the two variables are stored on different locations in the stack.
@russoue If you follow C++ rules then you'll find it becomes intuitive. I'm quite addicted to these C++ things. :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.