L'identificatore della funzione noexcept
ha lo scopo di migliorare le prestazioni a causa del potenziale codice di conservazione delle eccezioni nell'oggetto generato e, pertanto, dovrebbe essere aggiunto alle dichiarazioni e alle definizioni delle funzioni quando possibile? Penso ai wrapper per gli oggetti chiamabili, in primo luogo, dove noexcept
potrebbe fare qualche differenza, anche se le espressioni di controllo potrebbero "ingigantire" il codice sorgente. Ne vale la pena?Non eccede il miglioramento delle prestazioni?
risposta
I compilatori principali producono codice che è già ottimizzato molto simile al codice che non può essere generato, e quindi il caso in cui si verifica un'eccezione viene gestito dal codice non in linea che il meccanismo di gestione delle eccezioni trova guardando alla meta -Data riguardante la funzione. Suppongo che ci sia qualche vantaggio nella dimensione del codice per omettere questo quando si sa che non è necessario, però.
Probabilmente ci sono alcuni casi in cui una specifica nothrow fa permettere qualche ottimizzazione specifica:
int main() {
int i = 0;
try {
++i;
thing_that_cannot_throw();
++i;
thing_that_can_throw();
++i;
} catch (...) {}
std::cout << i << "\n";
}
Ecco la seconda ++ ho potuto in teoria essere riordinati prima della chiamata a thing_that_cannot_throw
(e i
solo inizializzato a 2
) . Comunque sia, in pratica è un'altra questione, dal momento che un'implementazione che fornisce garanzie sullo stato delle variabili nel debugger o nello stack sopra una chiamata di funzione, vorrebbe che abbia il valore 1
durante quella chiamata anche se è una variabile locale non osservabile con qualsiasi mezzo standard.
Sospetto che le garanzie di nothrow siano più preziose per il programmatore che per il compilatore. Se stai scrivendo un codice che offre la forte garanzia di eccezione, di solito ci saranno alcune operazioni critiche che esegui, che devi offrire la garanzia di nothrow (swap, mosse e distruttori sono i candidati comuni).
E, naturalmente, possiamo avere compilatori * di avviso * sull'avere delle eccezioni generate dalle funzioni 'noxcept' per aiutarci a superare la linea ... anche se sfortunatamente con il C++ il problema pervasivo di' new' essere in grado di lanciare impedisce molto: ( –
@MatthieuM c'è una nuova versione di new, non è così? – Martin
@Martin: c'è, cosa usa 'std :: string' comunque? Il problema è che non è possibile creare un nuovo' std :: string 'in un metodo' noexcept', non perché il tuo codice è difettoso, ma perché l'hardware su cui stai girando potrebbe essere più limitato.È piuttosto fastidioso –
In teoria, noexcept
migliorerebbe le prestazioni. Ma potrebbe anche causare alcuni problemi d'altra parte.
Nella maggior parte dei casi, non deve essere specificato perché i professionisti sono troppo pochi per essere considerati e potrebbe rendere doloroso l'aggiornamento del codice. This post, scritto da Andrzej, illustra i motivi in dettaglio.
Se è troppo lungo, basta prendere questi suggerimenti concludo da esso:
- funzioni Annotazione con
noexcept
se- sono stati annotati con
throw()
già, - o sono buoni candidati (elencati in post) e non buttare mai per certo,
- o sono costruttori di movimento, assegnazioni di spostamento la cui annotazione
noexcept
non può essere dedotta correttamente dal compilatore e le loro istanze sono supp osed da inserire in un contenitore STL.
- sono stati annotati con
- Non annotare le funzioni con
noexcept
se- siete veramente preoccupato per le prestazioni ridotte,
- o circa il rischio di chiamare
std::terminate
, - o non sono solo sicuro circa la nuova funzionalità ,
- o hai dei dubbi sul fatto che dovresti rendere la tua funzione
noexcept
o no.
penso che un compilatore potrebbe farlo, ma penso che il punto è quello di permettere ai modelli si comportano diversamente quando non possono generare un'eccezione (c'è un 'operatore noexcept' che restituisce' false' quando l'espressione argomento può restituire un'eccezione - non restituisce true se si ha una funzione che non verrà mai lanciata ma che non è contrassegnata con 'noexcept'). – Cubic
Se una funzione dichiarata come 'noexcept' lancia il programma deve terminare. Il compilatore deve inserire almeno un codice di gestione delle eccezioni per rilevare il problema e terminare il programma. –
@ DavidRodríguez-dribeas: quel codice può essere fuori linea, anche se (parte del runtime C++, anche). In linea di principio, il meccanismo di gestione delle eccezioni potrebbe far risalire lo stack e per ogni frame di chiamata, verificare se il suo codice è contrassegnato con un flag "no-outs". Forse con un'ulteriore complicazione per gestire chiamate in linea che non hanno il loro frame. Che sia quello che i compilatori fanno effettivamente per 'noxcept', non ne sono così sicuro, ma spesso è il modo in cui cercano i gestori di eccezioni e anche il lavoro da svolgere durante lo srotolamento dello stack. –