Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ - using const reference to prolong a member of a temporary, ok or UB?

consider something like this:

#include <iostream>  struct C {     C(double x=0, double y=0): x(x) , y(y) {         std::cout << "C ctor " << x << " " <<y << " "  << "\n";     }     double x, y; };  struct B {     B(double x=0, double y=0): x(x), y(y) {}     double x, y; };  struct A {     B b[12];      A() {         b[2] = B(2.5, 14);         b[4] = B(56.32,11.99);     } };   int main() {     const B& b = A().b[4];     C c(b.x, b.y); } 

when I compile with -O0 I'm getting the print

C ctor 56.32 11.99 

but when I compile with -O2 I'm getting

 C ctor 0 0 

I know we can use const reference to prolong a local temporary, so something like

const A& a = A(); const B& b = a.b; 

would be perfectly legal. but I'm struggling to find the reasoning for why the same mechanism/rule doesn't apply for any kind of temporary

EDIT FOR FUTURE REFERENCE:

I'm using gcc version 6.3.0

like image 966
user2717954 Avatar asked Sep 10 '19 07:09

user2717954


People also ask

Does const reference extend lifetime?

You are not questioning why const references are allowed to bind to temporaries, but merely why they extend the lifetime of those temporaries. If the lifetime of the temporary returned by bar() were not extended, then any usage of a (exemplified by the line (1)) would lead to undefined behavior.

When should we use a const reference and why?

Pass Using Const Reference in C++ Now, we can use the const reference when we do not want any memory waste and do not change the variable's value. The above code will throw a compile error as num = num +10 is passed as a const reference.

How do you reference a const?

You can declare the test function as: int test(gadget const &g); In this case, parameter g has type “reference to const gadget .” This lets you write the call as test(x) , as if it were passing by value, but it yields the exact same performance as if it were passing by address.

Does C support pass by constant reference?

C does not support references or passing by reference. You should use pointers instead and pass by address. Pass-by-value is efficient for primitive types, but does a shallow copy for structs. In C++ it makes a LOT of sense to pass objects by reference for efficiency.


1 Answers

Your code should be well-formed, because for temporaries

(emphasis mine)

Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference

Given A().b[4], b[4] is the subobject of b and the data member b is the subobject of the temproray A(), whose lifetime should be extended.

LIVE on clang10 with -O2
LIVE on gcc10 with -O2

BTW: This seems to be a gcc's bug which has been fixed.

From the standard, [class.temporary]/6

The third context is when a reference is bound to a temporary object.36 The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference if the glvalue to which the reference is bound was obtained through one of the following:

...

[ Example:

template<typename T> using id = T;  int i = 1; int&& a = id<int[3]>{1, 2, 3}[i];          // temporary array has same lifetime as a const int& b = static_cast<const int&>(0); // temporary int has same lifetime as b int&& c = cond ? id<int[3]>{1, 2, 3}[i] : static_cast<int&&>(0);                                            // exactly one of the two temporaries is lifetime-extended 

— end example ]

like image 69
songyuanyao Avatar answered Sep 24 '22 13:09

songyuanyao