Search code examples
c++language-lawyerobject-lifetimereference-binding

Is a const reference bound to another reference which is cast from temporary a dangling reference?


Below is the code snippet:

#include <iostream>
using namespace std;
struct B{
     int b;
     ~B(){cout <<"destruct B" << endl;}
};
B func(){
    B b;
    b.b = 1;
    return b;
}
int main(){
    const B& instance = (const B&)func(); //is `instance` a dangling reference?
    cout <<instance.b<<endl;
    return 0;
}

in this online compiler the output is

destruct B
destruct B
1

So the return value seems to destruct earlier than the cout operation. So the instance seems to be a dangling reference.

If we change const B& instance = (const B&)func(); to const B& instance =func();, then the result is

destruct B
1
destruct B

As a supplement, if I test the code in vs2015, then the output is the last one. However, if tested in gcc(before 4.6) ,the output is the former one,but latter one in version after 4.6. So I want to know whether the online compiler is wrong or the reference is dangling in fact.


Solution

  • According to the newest draft [class.temporary]/6 (irrelevant part is elided by me):

    The third context is when a reference is bound to a temporary object. 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:

    • ...

    • a const_­cast ([expr.const.cast]), static_­cast ([expr.static.cast]), dynamic_­cast ([expr.dynamic.cast]), or reinterpret_­cast ([expr.reinterpret.cast]) converting, without a user-defined conversion, a glvalue operand that is one of these expressions to a glvalue that refers to the object designated by the operand, or to its complete object or a subobject thereof,

    • ...

    ... [ Note: An explicit type conversion ([expr.type.conv], [expr.cast]) is interpreted as a sequence of elementary casts, covered above. [ Example:

    const int& x = (const int&)1;  // temporary for value 1 has same lifetime as x
    

    — end example ] — end note ]

    Your code is well-formed.


    Before C++14, the wording in the standard is unclear about such case, and there is a defect issue 1376. This issue clarifies the lifetime of the temporary object should not be extended in such case. However, this clarification is superseded by issue 1299 (whose resolution is not included even in C++17, but in the current draft).

    So you can conclude that before the resolution of issue 1299, it is a bug for GCC with version after 4.6. There is also a bug report 52202 for GCC.