4

I know lvalues can be converted into const reference. I'm curious if I can get a pointer to those lvalues.

If I write

const int* p = &3; //ERROR: lvalue required as unary operand '&'

I get this error. However,

const int* p = &((const int&)3);

this compiles. In this case, is the result of *p guaranteed to be 3?

eivour
  • 1,678
  • 12
  • 20
  • 2
    long story short - c-style cast almost always means at best implementation-defined behaviour, at worst undefined behaviour. – Richard Hodges Aug 27 '17 at 16:21
  • But this should compile with static_cast(3) too. – eivour Aug 27 '17 at 16:26
  • It does, but it's still UB. static_cast can only be used to cast back to the original type. – Richard Hodges Aug 27 '17 at 16:36
  • 4
    @RichardHodges That's nonsense. `static_cast` can perform a variety of casts between pairs of distinct types. `static_cast(3)` is, in itself, perfectly fine and legal. The UB arises out of trying to use an object after its lifetime has ended, not out of creating that object in the first place via a cast. – Igor Tandetnik Aug 27 '17 at 16:40
  • @IgorTandetnik you're right. It can perform a legal conversion. I was conflating static_cast with reinterpret_cast. – Richard Hodges Aug 27 '17 at 17:14

1 Answers1

8

This constructs a temporary int(3) and binds it to a const reference. p is made to point to that temporary. The lifetime of the temporary is extended to match that of the reference - but the reference itself is a temporary and is destroyed at the semicolon, leaving p a dangling pointer. Any attempt to use p afterwards (other than assigning a new value to it) would exhibit undefined behavior.

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
  • 1
    agree - demo here: https://godbolt.org/g/5nKT49 - `fooint` gets called with zero argument, not 3. – Richard Hodges Aug 27 '17 at 16:20
  • But this is legal, right? `const int& p = (const int&)3; const int* q = &p;` Might be worth mentioning. – AndyG Aug 27 '17 at 16:31
  • 2
    @AndyG Yes, I believe this is legal. It's just run of the mill temporary lifetime extension. One doesn't need a cast, could just write `const int& p = 3;` – Igor Tandetnik Aug 27 '17 at 16:37