Dovresti restituire per valore.
Lo standard ha una caratteristica specifica per migliorare l'efficienza del ritorno in valore. Si chiama "copy elision", e più specificamente in questo caso "named return value optimization (NRVO)".
I compilatori non devono implementarlo, ma anche in questo caso i compilatori non devono implementare la funzione inlining (o eseguire alcuna ottimizzazione). Ma le prestazioni delle librerie standard possono essere piuttosto scadenti se i compilatori non si ottimizzano e tutti i compilatori seri implementano inlining e NRVO (e altre ottimizzazioni).
Quando viene applicato NRVO, non ci sarà copia nel seguente codice:
std::vector<int> f() {
std::vector<int> result;
... populate the vector ...
return result;
}
std::vector<int> myvec = f();
Ma l'utente potrebbe voler fare questo:
std::vector<int> myvec;
... some time later ...
myvec = f();
L'elisione della copia non impedisce una copia qui perché è un'assegnazione piuttosto che un'inizializzazione. Tuttavia, dovresti comunque restituire per valore. In C ++ 11, l'assegnazione è ottimizzata da qualcosa di diverso, chiamato "semantica di spostamento". In C ++ 03, il codice sopra causa una copia e, sebbene in teoria un ottimizzatore possa essere in grado di evitarlo, in pratica è troppo difficile. Quindi, invece di myvec = f()
, in C ++ 03 dovresti scrivere questo:
std::vector<int> myvec;
... some time later ...
f().swap(myvec);
C'è un'altra opzione, che è quella di offrire un'interfaccia più flessibile all'utente:
template <typename OutputIterator> void f(OutputIterator it) {
... write elements to the iterator like this ...
*it++ = 0;
*it++ = 1;
}
È quindi possibile supportare anche l'interfaccia basata su vettori esistente oltre a ciò:
std::vector<int> f() {
std::vector<int> result;
f(std::back_inserter(result));
return result;
}
Questo potrebbe essere meno efficiente del codice esistente, se il codice esistente utilizza reserve()
in un modo più complesso di una semplice quantità fissa in anticipo. Ma se il codice esistente fondamentalmente richiama push_back
il vettore ripetutamente, allora questo codice basato su modello dovrebbe essere altrettanto buono.
f
?