Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding rvalue to non-const reference via pointer cast?

I don't understand how the following code compiles/doesn't compile:

struct Temp
{
  int i;
};

int main(int argc, char * argv[])
{
   //Temp &ref1 = (Temp){42}; // Error, as expected
   Temp &ref2 = *(Temp*)&(Temp){42}; // A-OK
   std::cerr << ref2.i << std::endl;
   return 0;
}

I'm using g++ 4.4.4.

like image 205
sfpiano Avatar asked Feb 21 '11 00:02

sfpiano


1 Answers

Your code is not really C++. It uses a compound literal which is a C99 feature. In C99 it evaluates to an lvalue and taking the address of the literal is completely fine there. Integrating this extension into C++, GCC appears to change the rule of it and make it an rvalue, better fitting the classification of them into the existing rules of C++ for usual casts that also produce rvalues.

GCC does not like &(Temp){42}, complaining that I take the address of a temporary. It's a warning about invalid code which it still accepts but does not really like. The same warning is given for other obviously-wrong code like &A(), which is a legal functional style C++ cast, which also produces an rvalue and thus cannot be used as the operand of the address-of operator.

The integration of compound literals into C++ by GCC also destroys the temporary prematurely, as can be seen by the following test

#include <iostream>
struct B {
  ~B() {
    std::cout << "~B" << std::endl;
  }
};
struct A { int i; B b; };

int main() {
  A *a = &(A){0};
  std::cout << "main" << std::endl;
}

In C99, the object that the literal refers to will be alive for the entire block (it will have automatic storage duration). In GNU C++ the object is destructed already at the end of the full expression, before the end of its block is even reached (the "~B" is printed before the "main").

like image 131
Johannes Schaub - litb Avatar answered Nov 01 '22 06:11

Johannes Schaub - litb