Ottimizzare C++/Ottimizzazione del codice C++: differenze tra le versioni
Contenuto cancellato Contenuto aggiunto
Nessun oggetto della modifica |
|||
Riga 115:
== Come diminuire il numero di istruzioni eseguite ==
=== Verifica di intervallo ===
=== 5.3.1. Per controllare se un numero intero “i” è compreso tra “min_i” e “max_i”, estremi inclusi, usa l’espressione “unsigned(i – min_i) <= unsigned(max_i – min_i)”. ===▼
▲
La suddetta formula è equivalente a quella più intuitiva:▼
<source lang=cpp>min_i <= i && i <= max_i</source>
Quest'ultima formula richiede due confronti, mentre quella suggerita ne richiede uno solo.
la quale tuttavia richiede due confronti invece di uno solo. In particolare, per controllare che un numero “i” sia valido come indice per accedere a un array di “size” elementi, si può scrivere l’espressione:▼
▲
<source lang=cpp>unsigned(i) < unsigned(size)</source>
Se le espressioni utilizzate sono già ti un tipo ''unsigned'', le conversioni non sono necessarie.
=== Ordine dei casi di ''switch'' ===
=== 5.3.2. Nelle istruzioni switch, poni i casi in ordine di probabilità decrescente. ===▼
Nella linea-guida 3.1.12 si consigliava di porre prima di casi più tipici, cioè quelli che si presume siano più probabili. Come ulteriore ottimizzazione, si dovrebbe contare, in esecuzioni tipiche, il numero di volte in cui viene eseguito ognuno dei singoli casi, e porre i casi in ordine da quello eseguito più volte a quello eseguito meno volte.▼
Nella linea-guida 3.1.12 si consigliava di porre prima di casi più tipici, cioè quelli che si presume siano più probabili.
=== 5.3.3. Se un certo valore intero è una costante nel codice applicativo, ma è una variabile nel codice di libreria, rendilo un parametro di template. ===▼
▲
=== Parametri interi di template ===
Supponi che stai scrivendo il seguente template di funzione di libreria, in cui sia x che y non hanno un valore definito in fase di sviluppo della libreria:▼
▲
<source lang=cpp>template <typename T> T f1(T x, T y) { return x * y; }</source>▼
▲Supponi che stai scrivendo
Tale funzione può essere chiamata dal seguente codice applicativo, nel quale x non ha un valore costante, ma y è la costante 4:
Line 141 ⟶ 150:
<source lang=cpp>int a = f1(b, 4);</source>
Se mentre scrivi la libreria sai che il chiamante ti passerà sicuramente una costante intera come argomento y, puoi trasformare
<source lang=cpp>
▲Se mentre scrivi la libreria sai che il chiamante ti passerà sicuramente una costante intera come argomento y, puoi trasformare il template nel seguente:
Tale funzione può essere chiamata dal seguente codice applicativo:
<source lang=cpp>int a = f2<
Tale chiamata istanzia automaticamente la seguente funzione:
Line 157 ⟶ 162:
<source lang=cpp>int f2(int x) { return x * 4; }</source>
Questa funzione è più veloce della precedente istanza di ''f1'', per i seguenti motivi:
* Viene passato un solo parametro alla funzione (''x'') invece di due (''x'' e ''y'').
* La divisione per una costante intera (''4'') è più veloce della divisione per una variabile intera (''y'').
* Dato che il valore costante (''4'') è una potenza di due, il compilatore, invece di eseguire una moltiplicazione intera, esegue uno scorrimento di bit
In generale, i parametri di template interi sono delle costanti per chi istanzia il template e quindi per il compilatore, e le costanti sono gestite in modo più efficiente delle variabili
Inoltre, alcune operazioni su costanti vengono calcolate in fase di compilazione.
Se invece di avere una funzione avevi già un template di funzione, basta aggiungere un ulteriore parametro a tale template.
=== Il ''Curiously Recurring Template Pattern'' ===
▲In generale, i parametri di template interi sono delle costanti per chi istanzia il template e quindi per il compilatore, e le costanti sono gestite in modo più efficiente delle variabili. Inoltre, alcune operazioni su costanti vengono calcolate in fase di compilazione.
Supponi che stai scrivendo la seguente classe base di libreria:
Line 219 ⟶ 229:
* per ogni derivazione di Base tutto il codice di Base viene duplicato.
=== Il pattern ''Strategy'' ===
=== 5.3.5. Se un oggetto che implementa il pattern strategy (detto anche policy) è una costante nel codice applicativo, ma il codice di libreria deve poter gestire più strategie, rendi la classe di tale oggetto un parametro di template. ===▼
▲
Supponi che stai scrivendo il seguente codice di libreria, che implementa il pattern strategy,▼
▲Supponi che stai scrivendo il seguente codice di libreria, che implementa il design pattern
<source lang=cpp>
class C;
Line 238 ⟶ 250:
};
</source>
<source lang=cpp>
class MyStrategy: public Strategy {
Line 252 ⟶ 266:
c.f(); // Esecuzione con strategia assegnata.
</source>
In tal caso, è possibile convertire il precedente codice di libreria nel seguente:
<source lang=cpp>
template <class Strategy>
class C {
public:
Line 273 ⟶ 288:
c.f(); // Esecuzione con strategia preassegnata.
</source>
In tal modo, si evita l'oggetto-strategia, e si ha il binding statico delle funzioni membro MyStrategy::is_valid e MyStrategy::run, cioè si evitano chiamate a funzioni virtuali.
Tuttavia, tale soluzione non consente
=== Operatori bit-a-bit ===
Gli operatori bit-a-bit (
== 5.4. Come ridurre le costruzioni e distruzioni di oggetti ==
|