2015-09-27 13 views
14

gcc, clang e VS2015 non mi Elide la chiamata al costruttore mossa nel seguente codice, dopo aver lanciato oggetto a. Mi sembra che le condizioni stabilite nel punto (31.2) del §8.12 [class.copy]/31 (N4140) siano soddisfatte.C'è qualche motivo speciale per cui il costruttore di movimento non viene elidato nello snippet mostrato di seguito?

#include <iostream> 

struct A 
{ 
    A() { std::cout << "Default ctor " << '\n'; } 
    A(const A& a) { std::cout << "Copy ctor" << '\n'; } 
    A(A&& a) { std::cout << "Move ctor" << '\n'; } 
    ~A() { std::cout << "Destructor " << '\n'; } 
}; 

int main() 
{ 
    try 
    { 
     A a; 
     throw a; 
    } 
    catch(A& a) { std::cout << "Caught" << '\n'; } 
} 

noti che a è un lvalue, ma secondo §12.8/32, risoluzione di sovraccarico per selezionare il costruttore per la copia viene eseguita prima come se l'oggetto fosse designato dalla rvalue. Cioè, la chiamata al costruttore di movimento è OK. Se si cancella la definizione del costruttore di mosse sopra, viene invocato il costruttore di copia, ma, di nuovo, non viene eliminato!

Capisco che la copia-elisione non è richiesta dallo Standard, ma sono curioso di sapere se c'è qualche condizione speciale che potrebbe giustificare il fatto, che i tre compilatori sopra menzionati evitino questa ottimizzazione, in questo particolare esempio .

Un'uscita esempio per gcc, dal link sopra:

g ++ -std = C++ 14 -O2 -Wall -pedantic -pthread main.cpp & & ./a.out

default ctor

Spostare ctor

Destructor

Ca effettuato l 'acquisto

Destructor

+1

è lungo il percorso d'eccezione, chi se ne frega? l'equivalente [percorso felice] (http://coliru.stacked-crooked.com/a/44bf1d21b3e185ba) ottimizza completamente – TemplateRex

+0

penserei si tratta di una formulazione che una variabile locale non può essere eliso se la sua costruzione ha effetti collaterali. Non sono sicuro che ci sia davvero un conflitto ma come regole semplici potrebbero essere effettivamente in conflitto per il compilatore. –

+2

@ Cheersandhth.-Alf: Copia-elisione è esplicitamente consentita in modo che il compilatore possa farlo anche se ci sono effetti collaterali. –

risposta

3

Secondo 12.8 [class.copy] paragrafo 31, secondo punto la copia di una variabile locale viene gettato può essere tralasciata:

in un rimessa espressione , quando l'operando è il nome di un oggetto automatico non volatile (diverso da un parametro di funzione o catch clausola) il cui campo di applicazione non si estende oltre l'estremità della più interna racchiude try-block (se presente), il copia/sposta l'operazione dall'operando all'oggetto eccezione (15.1) può essere omessa costruendo l'oggetto automatico direttamente nell'oggetto eccezione

Sembra che nessuno dei compilatori utilizzi questa ottimizzazione. Una delle ragioni potrebbe essere che semplicemente non vale la pena di fare finchè lo sforzo è meglio speso per altre ottimizzazioni. Non penso che ci sia qualcosa nello standard che vieta questa ottimizzazione.

+0

Una ragione pratica per non farlo è che questo può ** riordinare si de effetti **, dove qualcosa che la costruzione della variabile locale fa e che le seguenti affermazioni prima del tiro dipendono da, viene spostato al lancio. –

+0

Lo standard rilevante per quello è in C++ 11 §3.7.3, affermando che l'oggetto locale (e gli effetti collaterali della sua costruzione, da cui dipendono le seguenti affermazioni) possono essere eliminati, "Se una variabile con durata di archiviazione automatica ha inizializzazione o un distruttore con effetti collaterali, non deve essere distrutto prima della fine del suo blocco, né deve essere eliminato come ottimizzazione anche se sembra non essere utilizzato, tranne che * un oggetto di classe o la sua copia/mossa può essere eliminato come specificato in 12.8 * ". –

+0

Wow, sono sorpreso che ci sia una disposizione distinta per questo caso. Bella scoperta. –