Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Throwing an rvalue

Consider the fragment:

try {
    Foo f;
    throw std::move(f);
}
catch (Foo& f) { }

[expr.throw] says that:

the type of the exception object is determined by removing any top-level cv-qualifiers from the static type of the operand and adjusting the type from “array of T” or “function returning T” to “pointer to T” or “pointer to function returning T”, respectively.

which would be Foo&&. The exception object is then initialized according to [except.throw]:

Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler (15.3). If the type of the exception object would be an incomplete type or a pointer to an incomplete type other than (possibly cv-qualified) void the program is ill-formed.

This suggests to me that the exception object is initialized as:

Foo&& __exception_object = std::move(f);

and that the handler would not match. However, both gcc and clang do catch this exception. So what's the actual type of the exception object here? If Foo, why?

like image 811
Barry Avatar asked Sep 24 '15 12:09

Barry


1 Answers

The static type of an expression is never a reference type.

1.3.24 [defns.static.type] defines "static type":

type of an expression (3.9) resulting from analysis of the program without considering execution semantics

the first step in that "analysis of the program" is to remove references, see 5 [expr] p5 and Expressions can have reference type

If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.

So std::move(f) is an xvalue expression, with static type Foo.

You don't need to involve rvalues to demonstrate this, the same was true in C++03 with:

int& f();
throw f();

This throws an int not an int&.

Without considering the specifics, an exception object is an object, and a reference is not an object, so an exception object cannot be a reference. It must be an object.

like image 184
Jonathan Wakely Avatar answered Nov 08 '22 17:11

Jonathan Wakely