Ottimizzare C++/Ottimizzazione del codice C++/Supporto run-time

Indice del libro

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

modifica

Usa 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

modifica

Se 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

modifica

Usa 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.