Ottimizzare C++/Ottimizzazione del codice C++/Costruzioni e distruzioni: differenze tra le versioni
Contenuto cancellato Contenuto aggiunto
m Bot: Aggiungo: en:Optimizing C++/Code optimization/Constructions and destructions |
Nessun oggetto della modifica |
||
Riga 2:
Spesso capita che per elaborare un'espressione venga creato un oggetto temporaneo, che viene distrutto alla fine della stessa espressione in cui viene creato.
Se tale oggetto è di un tipo fondamentale, il compilatore quasi sempre riesce a evitarne la creazione, e comunque la creazione e la distruzione di un oggetto di un tipo fondamentale sono abbastanza veloci.
In questa sezione si descrivono alcune tecniche per evitare che siano creati oggetti temporanei di tipo composito, e quindi che siano chiamati i relativi costruttori e distruttori.
=== Valore di ritorno di funzioni ===
'''Per le funzioni che non siano espanse ''inline'', cerca di dichiarare
Nella compilazione di una funzione non espansa ''inline'', il compilatore non può sapere se il valore di ritorno verrà usato, e quindi lo deve comunque generare.
Generare un
Se
Comunque, se si costruisce l'oggetto da ritornare nelle stesse istruzioni <code>return</code>, senza quindi assegnare tale valore a una variabile, si sfrutta l'ottimizzazione garantita dallo standard detta ''Return Value Optimization'', che previene la creazione di oggetti temporanei.
Alcuni compilatori riescono a evitare la creazione di oggetti temporanei, anche se questi sono legati a variabili locali (con la cosiddetta ''Named Return Value Optimization''), ma in generale questo non è garantito e ha comunque alcune limitazioni.
Per verificare se viene attuata una di tali ottimizzazioni, incrementa un contatore statico nei costruttori,
Nel caso non risultassero applicate ottimizzazioni, ricorri a una delle seguenti tecniche alternative:
* Rendi la funzione <code>void</code>, e aggiungile un argomento passato per riferimento, che funge da valore di ritorno.
* Trasforma la funzione in un costruttore del tipo ritornato, che riceve gli stessi parametri della funzione.
* Fai in modo che la funzione restituisca un oggetto di un tipo ausiliario che ruba le risorse e le cede all'oggetto destinazione, senza copiarle.
* Usa un [[w:en:Expression_template|''expression template'']], che è una tecnica avanzata, facente parte del paradigma di programmazione detto [[w:en:Template metaprogramming|Template metaprogramming]].
*
=== Spostamento di variabili all'esterno di cicli ===
'''Se una variabile è dichiarata all'interno di un ciclo, e l'assegnamento ad essa costa di meno di una costruzione
Se la variabile è dichiarata all'interno del ciclo, l'oggetto associato ad essa viene costruito e distrutto a ogni iterazione, mentre se è esterna al ciclo, tale oggetto viene costruito e distrutto una volta sola,
Tuttavia, in molti casi un assegnamento costa esattamente quanto una coppia costruzione+distruzione, per cui in tali casi non ci sono vantaggi a spostare la dichiarazione all'esterno e aggiungere un assegnamento all'interno.
Line 36 ⟶ 37:
=== Operatore di assegnamento ===
'''In un overload dell'operatore di assegnamento (operator=), se sei sicuro che non solleverà eccezioni,
La tecnica più efficiente per copiare un oggetto è imitare
Pertanto, se c'è la possibilità che durante la copia venga sollevata un'eccezione, si deve usare una tecnica ''exception-safe'', che tuttavia non avrà prestazioni ottimali.
La tecnica di assegnamento ''exception-safe'' più elegante è
Viene mostrata dal seguente codice, nel quale <code>C</code> rappresenta il nome della classe, e <code>swap</code> una funzione membro che dovrà essere definita:
<source lang=cpp>
Line 53 ⟶ 56:
=== Overload per evitare conversioni ===
'''
Supponiamo di aver scritto la seguente funzione:
<source lang=cpp>
int f(const std::string& s) { return s[0]; }
</source>
il cui scopo è consentire di scrivere il segueente codice:
<source lang=cpp>
std::string s("abc");
int n = f(s);
</source>
Tale funzione può però essere usata anche dal seguente codice:
<source lang=cpp>
int n = f(string("abc"));
</source>
E, grazie alla conversione implicita da <code>char*</code> a <code>std::string</code>, può essere usata anche dal seguente codice:
<source lang=cpp>
int n = f("abc");
</source>
Entrambe le due ultime chiamate alla funzione <code>f</code> sono inefficienti, perché creano un oggetto temporaneo <code>std::string</code> non vuoto.
Per mantenere l'efficienza della prima chiamata dell'esempio, si dovrebbe definire anche la seguente funzione in overload:
<source lang=cpp>
int f(const char* s) { return s[0]; }
</source>
In generale, se una funzione è chiamata passandole un argomento di un tipo non consentito ma che può venire implicitamente convertito a un tipo consentito, viene creato un oggetto temporaneo del tipo consentito.
[[Categoria:Ottimizzare C++|Costruzioni e distruzioni]]
|