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?
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 toT
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With