Ottimizzare C++/Ottimizzazione del codice C++/Numero di istruzioni: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
RamaccoloBot (discussione | contributi)
m Bot: Sostituzione automatica (-[[Categoria:Ottimizzare C++|Ottimizzare C++/ +[[Categoria:Ottimizzare C++|)
Nessun oggetto della modifica
Riga 2:
 
Anche i costrutti che generano del codice espanso ''inline'' possono avere un costo significativo, in quanto tali istruzioni devono pur essere eseguite.
QuiIn questa sezione si descrivono le tecniche per ridurre il numero complessivo di istruzioni che il processore dovrà eseguire per eseguire una data operazione.
 
=== Verifica di intervallo ===
Riga 18:
<source lang=cpp>unsigned(i) < unsigned(size)</source>
 
SeOvviamente, se le espressioni utilizzate sono già di un tipo <code>unsigned</code>, le conversioni non sono necessarie.
 
=== Ordine dei casi di istruzioni <code>switch</code> ===
Riga 24:
'''Nelle istruzioni <code>switch</code>, poni i casi in ordine di probabilità decrescente.'''
 
Nella linea-guida "Ordine dei casi dell'istruzione <code>switch</code>" del capitolo 3.1.12, si consigliava già 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.
 
Riga 31:
'''Se un certo valore intero è una costante nel codice applicativo, ma è una variabile nel codice di libreria, rendilo un parametro di template.'''
 
Supponi che stai scrivendo la seguente funzione di libreria, in cui sia <code>x</code> che <code>y</code> non hanno un valore definito in fase di sviluppo della libreria:
 
<source lang=cpp>int f1(int x, int y) { return x * y; }</source>
 
Tale funzione può essere chiamata dal seguente codice applicativo, nel quale <code>x</code> non ha un valore costante, ma <code>y</code> è la costante 4:
 
<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 <code>y</code>, puoi trasformare la funzione nel seguente template di funzione:
 
<source lang=cpp>template <int Y> int f2(int x) { return x * Y; }</source>
Riga 51:
<source lang=cpp>int f2(int x) { return x * 4; }</source>
 
QuestaQuest'ultima funzione è più veloce della precedente istanzafunzione di ''<code>f1''</code>, per i seguenti motivi:
* Viene passato un solo parametro alla funzione (''<code>x''</code>) invece di due (''<code>x''</code> e ''<code>y''</code>).
* La divisione per una costante intera (''4'') è più veloce della divisione per una variabile intera (''<code>y''</code>).
* 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.
Riga 63:
=== Il ''Curiously Recurring Template Pattern'' ===
 
'''Se devi scrivere una classe base astratta di libreria tale che in ogni algoritmo nel codice applicativo si userà una sola classe derivata da tale classe base, usa il [[w:en:Curiously recurring template pattern|''Curiously Recurring Template Pattern'']].'''
 
Supponi che stai scrivendo la seguente classe base di libreria:
Riga 75:
</source>
 
In questa classe, la funzione <code>g</code> esegue un algoritmo che usa una chiamata a <code>f</code> come punto di personalizzazione dell'algoritmo.
Lo scopo di questa classe è consentire di scrivere il seguente codice applicativo:
 
<source lang=cpp>
Line 109 ⟶ 110:
</source>
 
In tal modo, si ha binding statico della funzione membro <code>Derivata1::f</code> alla funzione membro <code>Base<Derivata1>::g</code>, cioè la chiamata a tale funzione non è di tipo <code>virtual</code>, e può essere espansa ''inline''.
 
Tuttavia, con questa soluzione, se si volesse aggiungere la seguente definizione:
 
<source lang=cpp>
class Derivata1Derivata2: public Base<Derivata1Derivata2> {
public:
void f() { ... }
Line 120 ⟶ 121:
</source>
 
non risulterebbe possibile definire un puntatore o riferimento a una classe base comune a <code>Derivata1</code> e <code>Derivata2</code>, in quanto tali classi risultano due tipi senza alcuna relazione; quindidi conseguenza, questa soluzione non è adatta se si vuole permettere al codice applicativo di definire un contenitore di oggetti arbitrari derivati da Base.
 
Altre limitazioni sono le seguenti:
* <code>Base</code> è necessariamente un tipo astratto;
* un oggetto di tipo </code>Derivata1</code> non può essere convertito in un oggetto di tipo <code>Derivata2</code> o viceversa;
* per ogni derivazione di <code>Base</code>, tutto il codice macchina di <code>Base</code> viene duplicato.
 
=== Il pattern ''Strategy'' ===
 
'''Se un oggetto che implementa il pattern [[w:Strategy pattern|''Strategy'']] (noto anche come pattern ''Policy'') è una costante in ogni algoritmo nel codice applicativo, ma il codice di libreria deve poter gestire più strategie, elimina tale oggetto, rendi <code>static</code> tutti i suoi membri, e aggiungi tale classe come parametro di template.'''
 
Supponi che stai scrivendo il seguente codice di libreria, che implementa il design pattern ''Strategy'':
Line 159 ⟶ 160:
};
...
MyStrategy s; // Oggetto che rappresenta la mia strategia.
C c; // Oggetto contenente un algoritmo con strategia personalizzabile.
c.set_strategy(s); // Assegnazione della strategia.
c.f(); // Esecuzione dell'algoritmo con strategia assegnata.
</source>
 
Line 171 ⟶ 172:
class C {
public:
void f() {
if (Strategy::is_valid(*this)) Strategy::run(*this); }
}
};
</source>
Line 195 ⟶ 198:
=== Operatori bit-a-bit ===
 
'''Dovendo eseguire operazioni booleane su un insieme di singoli bit, affianca tali bit in unaun variabileoggetto di tipo “unsigned<code>unsigned int”int</code>, e usa gli operatori bit-a-bit su tale oggetto.'''
 
Gli operatori bit-a-bit (''<code>&''</code>, ''<code>|''</code>, ''<code>^''</code>, ''<code><''<</code>, e ''<code>>''></code>) sono tradotti in singole istruzioni veloci, e operano su tutti i bit di un registro in una sola istruzione.
 
[[Categoria:Ottimizzare C++|Ottimizzazione del codice C++/Numero di istruzioni]]
{{Avanzamento|75100%|2326 maggio 2008}}