2015-09-24 11 views
13

consideri il frammento:gettando un rvalue

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

[expr.throw] dice che:

il tipo dell'oggetto eccezione è determinata da rimuovere qualsiasi livello superiore CV-qualificazioni dal tipo statico dell'operando e la regolazione del tipo da "matrice di T" o "funzione di ritorno T" a "puntatore a T" o "puntatore a funzione di ritorno T", rispettivamente.

che sarebbe Foo&&. L'oggetto eccezione viene inizializzata secondo [except.throw]:

un'eccezione copia-inizializza (8.5, 12.8) un oggetto temporaneo, definito oggetto eccezione. Il temporaneo è un lvalue e viene utilizzato per inizializzare la variabile dichiarata nel gestore corrispondente (15,3). Se il tipo dell'oggetto eccezione è un tipo incompleto o un puntatore a un tipo incompleto diverso da (possibilmente qualificato cv) void il programma è mal formato.

Questo mi fa pensare che l'oggetto eccezione viene inizializzato come:

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

e che il gestore non sarebbe partita. Tuttavia, sia gcc che clang catturano questa eccezione. Quindi qual è il tipo effettivo dell'oggetto eccezione qui? Se Foo, perché?

+5

Perché il downvote? – Barry

risposta

14

Il tipo statico di un'espressione non è mai un tipo di riferimento.

1.3.24 [defns.static.type] definisce "tipo statico":

tipo di espressione (3.9) risultante dall'analisi del programma senza considerare semantica esecuzione

la primo passo in tale "analisi del programma" è rimuovere riferimenti vedi 5 [expr] p5 e Expressions can have reference type

Se un'espressione ha inizialmente il tipo "riferimento a T" (8.3.2, 8.5.3), il tipo viene regolato su T prima di qualsiasi ulteriore analisi. L'espressione designa l'oggetto o la funzione denotata dal riferimento e l'espressione è un lvalue o un valore x, a seconda dell'espressione.

Quindi std::move(f) è un'espressione xvalue, con tipo statico Foo.

Non è necessario coinvolgere rvalues ​​per dimostrare questo, lo stesso era vero in C++ 03 con:

int& f(); 
throw f(); 

Questo genera non int un int&.

Senza considerare le specifiche, un oggetto di eccezione è un oggetto e un riferimento non è un oggetto, quindi un oggetto di eccezione non può essere un riferimento. Deve essere un oggetto.