Is casting a temporary with type `int` to a reference safe?

馋奶兔 提交于 2019-12-10 22:25:55

问题


In the following program:

int Func()
{
    int a = { 10 };
    return a;
}
int main()
{  
    int& r = (int&)(const int&)Func();
    r = 5;        
}

r is a reference to a temporary of type int. But temporaries are destroyed immediately unless they are assigned normally to a reference. The assignment above does not seem normal. Is it safe to use r in Standard C++?


回答1:


Introduction: the C-style casts are equivalent to (C++17 [expr.cast]):

int& r = const_cast<int&>( static_cast<const int&>(Func()) );

In the subexpression static_cast<const int&>(Func()) the behaviour is described by C++17 [expr.static.cast]/4 (where T is the type being cast to):

If T is a reference type, the effect is the same as performing the declaration and initialization T t(e); for some invented temporary variable t (11.6) and then using the temporary variable as the result of the conversion

In this case T is const int&, so the initialization of the reference is similar to const int& t(Func());.

Now there's two issues in this code:

  • The type of the temporary
  • The lifetime of the temporary involved

The type of the temporary is const int (C++17 [dcl.init.ref]/5.2.1.2). So your code causes undefined behaviour by modifying a const object. Link to other SO question on this topic

For the rest of this answer (addressing the lifetime issue) I'll assume you change r = 5 to some statement that only reads r.


The behaviour of the reference chaining changed with the application of CWG 1299. The defect was filed in April 2011 and resolved in March 2017. The resolution did not appear in C++17 (N4659); it appears only in post-C++17 drafts.

The resolution has status DRWP, my understanding of this is that it means it retroactively applies to C++17 but not to C++14 (if someone wants to confirm or correct this that would be great).


Anyway, this resolution enables lifetime extention over reference chains in some circumstances. The wording is (N4762 class.temporary/6):

[...] 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, static_cast, dynamic_cast, or 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,

Prior to CWG1299 this paragraph only applied to initializing a reference from a prvalue, but now it can apply to cases of initializing a reference from any expression category if the designated object is a temporary object.

Note that the way temporary materialization works in C++17 is that the prvalue is converted to an xvalue when materialization happens, and this xvalue is the glvalue referred to by the bold text above.

There is even an example included now to confirm this:

const int& b = static_cast<const int&>(0); // temporary int has same lifetime as b

The behaviour of compilers shown in another deleted answer must be applying the resolution of CWG1299.



来源:https://stackoverflow.com/questions/54736807/is-casting-a-temporary-with-type-int-to-a-reference-safe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!