2010-01-27 1 views
29

Stavo leggendo Copy and Swap.Cos'è la copia elision e come ottimizza l'idioma copy-and-swap?

Ho provato a leggere alcuni collegamenti su Copia Elision ma non sono riuscito a capire correttamente cosa significasse. Qualcuno può spiegare che cosa questa ottimizzazione è, e soprattutto cosa si intende con il seguente testo di

Questo non è solo una questione di convenienza, ma in realtà un'ottimizzazione. Se il/i parametro/i si lega a un lvalue (un altro oggetto non const), una copia dell'oggetto viene creata automaticamente durante la creazione dei parametri. Tuttavia, quando si associa a un valore rvalue (oggetto temporaneo, letterale), la copia viene in genere eliminata, consentendo di salvare una chiamata a un costruttore di copia e un distruttore. Nella versione precedente dell'operatore di assegnazione in cui il parametro è accettato come riferimento const, elisione copia non si verifica quando il riferimento si lega a un valore. Ciò si traduce in un oggetto aggiuntivo creato e distrutto.

+0

Correlati: [Cos'è la copia elision?] (Http://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization) –

risposta

33

Il costruttore di copie esiste per fare copie. In teoria, quando si scrive una riga come:

CLASS c(foo()); 

Il compilatore avrebbe dovuto chiamare il costruttore di copia per copiare il ritorno di foo() in c.

Copia elision è una tecnica per saltare la chiamata al costruttore di copie in modo da non pagare l'overhead.

Ad esempio, il compilatore può disporre che foo() costruisca direttamente il suo valore di ritorno in c.

Ecco un altro esempio. Diciamo che si dispone di una funzione:

void doit(CLASS c); 

Se lo si chiama con un argomento attuale, il compilatore deve invocare il costruttore di copia in modo che il parametro originale non può essere modificato:

CLASS c1; 
doit(c1); 

Ma ora prendere in considerazione un esempio diverso, diciamo che si chiama la funzione in questo modo:

doit(c1 + c1); 

operator+ sta andando ad avere per creare un oggetto temporaneo (un rvalue). Invece di invocare il costruttore di copie prima di chiamare doit(), il compilatore può passare il temporaneo creato da operator+ e passarlo invece a doit().

2

Ecco un esempio:

#include <vector> 
#include <climits> 

class BigCounter { 
public: 
    BigCounter &operator =(BigCounter b) { 
     swap(b); 
     return *this; 
    } 

    BigCounter next() const; 

    void swap(BigCounter &b) { 
     vals_.swap(b); 
    } 

private: 
    typedef ::std::vector<unsigned int> valvec_t; 
    valvec_t vals_; 
}; 

BigCounter BigCounter::next() const 
{ 
    BigCounter newcounter(*this); 
    unsigned int carry = 1; 
    for (valvec_t::iterator i = newcounter.vals_.begin(); 
     carry > 0 && i != newcounter.vals_.end(); 
     ++i) 
    { 
     if (*i <= (UINT_MAX - carry)) { 
     *i += carry; 
     } else { 
     *i += carry; 
     carry = 1; 
     } 
    } 
    if (carry > 0) { 
     newcounter.vals_.push_back(carry); 
    } 
    return newcounter; 
} 

void someFunction() 
{ 
    BigCounter loopcount; 
    while (true) { 
     loopcount = loopcount.next(); 
    } 
} 

In somefunction linea loopcount = loopcount.next(); benefici notevolmente da copia elision. Se l'elisione di copia non fosse consentita, quella linea richiederebbe 3 invocazioni del costruttore di copie e una chiamata associata a un distruttore. Con copia elision consentita, può essere ridotta a 1 chiamata del costruttore di copie, quella esplicita all'interno di BigCount::next() dove viene dichiarato newcounter.

Se operator = era stato dichiarato e definito in questo modo:

BigCounter &BigCounter::operator =(const BigCounter &b) { 
    BigCounter tmp(b); 
    swap(tmp); 
    return *this; 
} 

ci sarebbe avuto di essere stato 2 invocazioni del costruttore di copia, anche con copia elision. Uno per costruire newcounter e l'altro per costruire tmp. E senza copia elision ci sarebbe ancora 3. Ecco perché dichiarare operator = quindi il suo argomento richiede il richiamo del costrutto di copia può essere un'ottimizzazione quando si utilizza l'idioma 'copia e swap' per l'operatore di assegnazione. Quando viene invocato il costruttore di copie per la costruzione di un argomento, è possibile elidere la sua invocazione, ma se è invocato per creare una variabile locale, potrebbe non esserlo.

Problemi correlati