Ottimizzare C++/Ottimizzazione del codice C++/Supporto run-time
Le routine del supporto run-time del linguaggio C++ hanno ovviamente un costo significativo, in quanto altrimenti tali funzionalità sarebbero state espanse inline.
In questa sezione si presentano tecniche per evitare costrutti che comportano la chiamata implicita di costose routine del supporto run-time.
L'operatore typeid
modifica
Invece di usare l'operatore typeid
, usa una funzione virtual
.
Tale operatore può richiedere un tempo superiore a quello richiesto da una semplice chiamata a funzione.
L'operatore dynamic_cast
modifica
Invece dell'operatore dynamic_cast
, usa l'operatore typeid
, o, ancora meglio, una funzione virtual
.
Tale operatore può richiedere un tempo notevolmente superiore a quello richiesto da una semplice chiamata a funzione, e maggiore perfino di quello richiesto dall'operatore typeid
.
La specifica di eccezioni vuota
modificaUsa la specifica di eccezioni vuota (cioè aggiungi throw()
dopo la dichiarazione) alle funzioni di cui sei certo che non solleveranno eccezioni.
Alcuni compilatori utilizzano tale informazione per ottimizzare la contabilità necessaria per gestire le eventuali eccezioni.
Il costrutto try/catch
modifica
Sposta prima dei colli di bottiglia le istruzioni try
, e dopo i colli di bottiglia le corrispondenti istruzioni catch
.
In altre parole, estrai dai colli di bottiglia i blocchi try/catch
.
L'esecuzione di un blocco try/catch
talvolta ha costo zero, ma altre volte comporta un rallentamento. Evita di eseguire tale blocco all'interno dei colli di bottiglia.
Operazioni a virgola mobile o intere
modificaSe il processore target non contiene un'unità a virgola mobile, sostituisci le funzioni, costanti e variabili a virgola mobile con le corrispondenti funzioni, costanti e variabili intere; mentre se contiene un'unità a virgola mobile a precisione solamente singola, sostituisci funzioni, costanti e variabili di tipo double
con le corrispondenti di tipo float
.
Gli odierni processori per sistemi desktop e server contengono hardware dedicato all'aritmetica a virgola mobile, sia a precisione singola che doppia, per cui tali operazioni, sono pressoché altrettanto veloci quanto quelle su numeri interi.
Alcuni processori dedicati per sistemi embedded, invece, non contengono hardware dedicato all'aritmetica a virgola mobile, o contengono hardware in grado di gestire solo la precisione singola. Pertanto, in tali sistemi, le operazioni non disponibili in hardware vengono solamente emulate con lentissime funzioni di libreria. In tal caso, risulta molto più veloce utilizzare l'aritmetica intera, oppure, se disponibile in hardware, l'aritmetica a precisione singola.
Per gestire numeri decimali usando l'aritmetica intera si devono usare gli interi intendendoli moltiplicati per un fattore di scala. A tale scopo, ogni numero viene moltiplicato per tale fattore in fase di input e viene diviso per lo stesso fattore in fase di output, o viceversa.
Conversione da numero a stringa
modificaUsa funzioni ottimizzate per convertire numeri in stringa.
Le funzioni standard di conversione da numero intero a stringa e da numero a virgola mobile a stringa sono poco efficienti. Per svolgere velocemente tali operazioni, usa funzioni ottimizzate non-standard, eventualmente scritte da te.
Uso delle funzioni di cstdio
modifica
Per eseguire operazioni di input/output, invece di usare gli stream del C++, usa le vecchie funzioni del C, dichiarate nel file di intestazione cstdio
.
Le primitive di I/O del C++ sono state progettate principalmente per effettuare il controllo statico dei tipi (o type safety) e per consentire la personalizzazione per le proprie classi invece che per le prestazioni, e molte loro implementazioni risultano essere piuttosto inefficienti.
In particolare, le funzioni di I/O del linguaggio C fread
e fwrite
sono più efficienti delle funzioni membro della classe fstream
read
e write
.