La restituzione per riferimento valore è più efficiente?


Risposte:


246
Beta_ab&&
Beta::toAB() const {
    return move(Beta_ab(1, 1));
}

Ciò restituisce un riferimento pendente, proprio come nel caso del riferimento lvalue. Dopo che la funzione ritorna, l'oggetto temporaneo verrà distrutto. Dovresti restituire Beta_abper valore, come il seguente

Beta_ab
Beta::toAB() const {
    return Beta_ab(1, 1);
}

Ora sta spostando correttamente un Beta_aboggetto temporaneo nel valore restituito della funzione. Se il compilatore può, eviterà del tutto lo spostamento, usando RVO (ottimizzazione del valore di ritorno). Ora puoi fare quanto segue

Beta_ab ab = others.toAB();

E si sposterà costruendo il temporaneo ab, o facendo RVO per omettere di fare una mossa o copiare del tutto. Ti consiglio di leggere BoostCon09 Rvalue References 101 che spiega la questione e come (N) RVO capita di interagire con questo.


Il tuo caso di restituzione di un riferimento di valore sarebbe una buona idea in altre occasioni. Immagina di avere una getAB()funzione che invochi spesso in modo temporaneo. Non è ottimale per farlo restituire un riferimento al valore costante per i temporali del valore. Puoi implementarlo in questo modo

struct Beta {
  Beta_ab ab;
  Beta_ab const& getAB() const& { return ab; }
  Beta_ab && getAB() && { return move(ab); }
};

Si noti che movein questo caso non è facoltativo, poiché abnon è né un valore locale automatico né un valore temporaneo. Ora, il qualificatore ref && afferma che la seconda funzione è invocata sui provvisori rvalue, facendo la seguente mossa, invece di copiare

Beta_ab ab = Beta().getAB();

51
Avevo sempre supposto che il problema del riferimento penzolante andasse via automaticamente quando il tipo di ritorno era un riferimento di valore r. Sono contento di averlo chiarito prima che mi mordesse. Gli stack che distruggono i bug fanno schifo.
deft_code

31
:) In realtà, i riferimenti al valore sono "solo riferimenti" come i riferimenti al valore. non copiano o archiviano nulla.
Johannes Schaub - litb

9
cosa funziona const & qualifier su un membro più di una semplice const?
galinette,


3
@galinette Questi sono ref-qualificazioni .
Malcolm,

2

Si può essere più efficiente, ad esempio, in un contesto diverso bit:

template <typename T>
T&& min_(T&& a, T &&b) {
    return std::move(a < b? a: b);
}

int main() {
   const std::string s = min_(std::string("A"), std::string("B"));
   fprintf(stderr, "min: %s\n", s.c_str());
   return 0;
}

Come osservazione interessante, sulla mia macchina clang++ -O3genera 54 istruzioni per il codice sopra rispetto a 62 istruzioni per il normale std::min. Tuttavia, con -O0esso genera 518 istruzioni per il codice sopra rispetto a 481 per il normale std::min.


Sono confuso dalla tua risposta. Avevo provato una versione simile (forse) ma non era riuscita: ideone.com/4GyUbZ Potresti spiegare perché?
Deqing,

È stato utilizzato il riferimento sull'oggetto temporaneo for(:)e l'integrazione sull'oggetto deallocato. Correzione: ideone.com/tQVOal
wonder.mice

3
questa risposta non è in realtà sbagliata? per il parametro template T, T&& non è un riferimento di valore r, ma piuttosto un riferimento universale, e in tal caso, dovremmo sempre chiamare std :: forward <T>, non std :: move! Per non parlare del fatto che questa risposta contraddice direttamente quella più votata sopra.
xdavidliu,

@xdavidliu questa risposta è un esempio inventato di come il ritorno per valore può essere più efficiente. std::move()è solo usato come cast esplicito per illustrare il punto più chiaramente. Non è un codice che potresti copiare e incollare nel tuo progetto. Non contraddice la risposta più votata, perché all'interno della funzione viene creato un oggetto temporaneo. Qui l'oggetto restituito è uno degli argomenti (gli oggetti temporanei vengono distrutti come l'ultimo passo nella valutazione dell'espressione completa che (lessicamente) contiene il punto in cui sono stati creati).
wonder.mice,

2
@ wonder.mice quindi si prega di sostituire T con std :: string; non è necessario utilizzare i modelli qui e usare T&& come riferimento di valore r è semplicemente uno stile terribile che confonde inutilmente le persone nuove con modelli e valori r.
xdavidliu,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.