Sono a conoscenza di 5 categorie generali in cui la ricompilazione di un compilatore C ++ 03 come C ++ 11 può causare aumenti delle prestazioni illimitati che sono praticamente estranei alla qualità dell'implementazione. Queste sono tutte variazioni della semantica del movimento.
std::vector riallocare
struct bar{
std::vector<int> data;
};
std::vector<bar> foo(1);
foo.back().data.push_back(3);
foo.reserve(10); // two allocations and a delete occur in C++03
ogni volta che il foobuffer viene riallocato in C ++ 03 viene copiato ogni vectorin bar.
In C ++ 11 sposta invece la bar::datas, che è sostanzialmente gratuita.
In questo caso, questo si basa su ottimizzazioni all'interno del stdcontenitore vector. In ogni caso di seguito, l'uso dei stdcontainer è dovuto al fatto che sono oggetti C ++ che hanno una movesemantica efficiente in C ++ 11 "automaticamente" quando si aggiorna il compilatore. Gli oggetti che non lo bloccano che contengono un stdcontenitore ereditano anche i movecostruttori automatici migliorati .
Fallimento NRVO
Quando NRVO (denominato ottimizzazione del valore restituito) fallisce, in C ++ 03 ricade sulla copia, su C ++ 11 ricade sulla mossa. I guasti di NRVO sono facili:
std::vector<int> foo(int count){
std::vector<int> v; // oops
if (count<=0) return std::vector<int>();
v.reserve(count);
for(int i=0;i<count;++i)
v.push_back(i);
return v;
}
o anche:
std::vector<int> foo(bool which) {
std::vector<int> a, b;
// do work, filling a and b, using the other for calculations
if (which)
return a;
else
return b;
}
Abbiamo tre valori: il valore restituito e due diversi valori all'interno della funzione. Elision consente di "unire" i valori all'interno della funzione con il valore restituito, ma non tra loro. Entrambi non possono essere uniti al valore di ritorno senza unirsi tra loro.
Il problema di base è che l'elissione della NRVO è fragile e che il codice con modifiche non vicine al returnsito può improvvisamente avere massicce riduzioni delle prestazioni in quel punto senza emettere diagnosi. Nella maggior parte dei casi di fallimento NRVO, C ++ 11 finisce con a move, mentre C ++ 03 finisce con una copia.
Restituzione di un argomento di funzione
Anche qui Elision è impossibile:
std::set<int> func(std::set<int> in){
return in;
}
in C ++ 11 è economico: in C ++ 03 non c'è modo di evitare la copia. Gli argomenti alle funzioni non possono essere elisi con il valore restituito, poiché la durata e la posizione del parametro e del valore restituito sono gestite dal codice chiamante.
Tuttavia, C ++ 11 può spostarsi dall'uno all'altro. (In un esempio meno giocattolo, si potrebbe fare qualcosa per set).
push_back o insert
Infine, l'elisione nei container non avviene: ma C ++ 11 sovraccarica il rvalue move inserendo operatori, che salva le copie.
struct whatever {
std::string data;
int count;
whatever( std::string d, int c ):data(d), count(c) {}
};
std::vector<whatever> v;
v.push_back( whatever("some long string goes here", 3) );
in C ++ 03 whateverviene creato un temporaneo , quindi viene copiato nel vettore v. std::stringVengono allocati 2 buffer, ognuno con dati identici e uno viene scartato.
In C ++ 11 whateverviene creato un temporaneo . Il whatever&& push_backsovraccarico è quindi movetemporaneo nel vettore v. Un std::stringbuffer viene allocato e spostato nel vettore. Un vuoto std::stringviene scartato.
Incarico
Rubato dalla risposta di @ Jarod42 qui sotto.
L'elisione non può avvenire con l'assegnazione, ma può spostarsi da.
std::set<int> some_function();
std::set<int> some_value;
// code
some_value = some_function();
qui some_functionrestituisce un candidato da cui fuggire, ma poiché non viene utilizzato per costruire direttamente un oggetto, non può essere eluso. In C ++ 03, quanto sopra si traduce nella copia del contenuto del temporaneo some_value. In C ++ 11, viene spostato in some_value, che in pratica è gratuito.
Per l'effetto completo di quanto sopra, è necessario un compilatore che sintetizzi i costruttori di movimenti e l'assegnazione per te.
MSVC 2013 implementa i costruttori di spostamento in stdcontenitori, ma non sintetizza i costruttori di spostamento sui tipi.
Quindi i tipi che contengono se std::vectorsimili non ottengono tali miglioramenti in MSVC2013, ma inizieranno a ottenerli in MSVC2015.
clang e gcc hanno da tempo implementato costruttori di mosse implicite. Il compilatore Intel 2013 supporterà la generazione implicita di costruttori di spostamenti se si passa -Qoption,cpp,--gen_move_operations(non lo fanno per impostazione predefinita nel tentativo di essere cross-compatibili con MSVC2013).