Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const reference to temporary reference

#include <iostream>
using namespace std;

struct CL
{
    CL()
    {
        cout<<"CL()"<<endl;
    }
    CL(const CL&)
    {
        cout<<"CL(const CL&)"<<endl;
    }
    ~CL()
    {
        cout<<"~CL()"<<endl;
    }
};

CL cl;

CL fnc()
{
    return cl;
}

int main() {
    cout<<"start"<<endl;
    const CL& ref=static_cast<const CL&>(fnc());
    //...Is "ref" valid here??
    cout<<"end"<<endl;
    return 0;
}

What's lifetime of temporary object returned by fnc()? Is it lifetime of "ref" or of temporary reference static_cast(fnc()), which destroyed at end of statement?

Output of gcc (lifetime of fnc() is lifetime of "ref"):

CL()  //global object "cl"
start
CL(const CL&)
end
~CL()
~CL() //global object "cl"

Output of VS2013 (lifetime of fnc() is lifetime of temporary reference):

CL()  //global object "cl"
start
CL(const CL&)
~CL()
end
~CL() //global object "cl"

What's correct by Standard?

like image 267
Denis Avatar asked Mar 20 '15 08:03

Denis


People also ask

Can reference variables be constant?

Once a reference variable has been defined to refer to a particular variable it can refer to any other variable. A reference is not a constant pointer.

What is constant reference?

A constant reference is an expression that evaluates to the value of the named constant. The simplest constant references are primary expressions—they consist simply of the name of the constant: CM_PER_INCH = 2.54 # Define a constant. CM_PER_INCH # Refer to the constant.

What are temporary objects C++?

A temporary object is an unnamed object created by the compiler to store a temporary value.

How to extend lifetime of object?

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.


1 Answers

I believe Visual Studio is correct here, this is covered in defect report #1376 which says:

In a declaration like

T&& r = static_cast<T&&>(T());

it is not clear what the lifetime of the T temporary should be. According to 5.2.9 [expr.static.cast] paragraph 4, the static_cast is equivalent to a declaration of an invented temporary variable t. The lifetime of the temporary is extended to that of t, but it is not clear what that lifetime should be, nor if the subsequent binding of t to r would affect the lifetime of the original temporary. (See also issue 1568.)

and the discussion includes this conclusion:

The reference is bound to the xvalue result of the static_cast, so the lifetime of the temporary is not extended and this example results in a dangling reference.

and defect report 1568 covers this case more specifically:

According to 12.2 [class.temporary] paragraphs 4-5,

There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression...

The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference...

It is not clear whether this applies to an example like the following:

struct S { };
const S& r = (const S&)S();

and the response was:

This issue is a duplicate of issue 1376.

so in this case:

const CL& ref=static_cast<const CL&>(fnc());

the reference is bound to the result of the static_cast and not to CL and therefore CL is a dangling reference.

For reference the relevant text from the draft C++11 standard section 5.2.9 [expr.static.cast]:

Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_- cast(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and only if the initialization uses it as a glvalue.

like image 174
Shafik Yaghmour Avatar answered Sep 21 '22 14:09

Shafik Yaghmour