2015-09-24 4 views
13

Considérons le fragment:Lancer une rvalue

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

[expr.throw] dit que:

le type de l'objet d'exception est déterminée par élimination de tout niveau supérieur cv-qualificatifs à partir du type statique de l'opérande et en ajustant le type de "array of T" ou "fonction retournant T" à "pointeur sur T" ou "pointeur sur fonction retournant T", respectivement.

qui serait Foo&&. L'objet d'exception est alors initialisé en fonction de [except.throw]:

lancer une exception copy-initialise (8.5, 12.8) d'un objet temporaire, appelé l'objet d'exception . Le temporary est une lvalue et est utilisé pour initialiser la variable déclarée dans le gestionnaire correspondant (15.3). Si le type de l'objet exception serait un type incomplet ou un pointeur vers un type incomplet autre que (éventuellement qualifié cv) void le programme est mal formé.

Cela me porte à croire que l'objet d'exception est initialisé comme:

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

et que le gestionnaire ne correspondrait pas à. Cependant, gcc et clang capturent cette exception. Alors, quel est le type réel de l'objet d'exception ici? Si Foo, pourquoi?

+5

Pourquoi le downvote? – Barry

Répondre

14

Le type statique d'une expression n'est jamais un type de référence.

03.01.24 [defns.static.type] définit type "statique":

type d'une expression (3.9) résultant de l'analyse du programme sans tenir compte de la sémantique d'exécution

la première étape dans cette « analyse du programme » est de supprimer les références, voir 5 [expr] p5 et Expressions can have reference type

Si une expression a d'abord le type "référence à T" (8.3.2, 8.5.3), le type est ajusté à T avant toute autre analyse. L'expression désigne l'objet ou la fonction désigné par la référence, et l'expression est une valeur lvalue ou une valeur x, en fonction de l'expression.

Donc std::move(f) est une expression xvalue, de type statique Foo.

Vous n'avez pas besoin d'impliquer rvalues ​​à démontrer, en était de même en C++ 03 avec:

int& f(); 
throw f(); 

Cela jette un int pas int&.Sans tenir compte des spécificités, un objet d'exception est un objet et une référence n'est pas un objet. Un objet d'exception ne peut donc pas être une référence. Ce doit être un objet.