Ist die Rückgabe per Wertreferenz effizienter?


Antworten:


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

Dies gibt eine baumelnde Referenz zurück, genau wie beim lvalue-Referenzfall. Nachdem die Funktion zurückgekehrt ist, wird das temporäre Objekt zerstört. Sie sollten Beta_abnach Wert wie folgt zurückgeben

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

Jetzt wird ein temporäres Beta_abObjekt ordnungsgemäß in den Rückgabewert der Funktion verschoben. Wenn der Compiler dies kann, wird er die Verschiebung mithilfe von RVO (Rückgabewertoptimierung) vollständig vermeiden. Jetzt können Sie Folgendes tun

Beta_ab ab = others.toAB();

Und es wird das temporäre Konstrukt verschieben aboder RVO ausführen, um das Verschieben oder Kopieren ganz zu unterlassen. Ich empfehle Ihnen, BoostCon09 Rvalue References 101 zu lesen , in dem die Angelegenheit erklärt wird und wie (N) RVO damit interagiert.


In anderen Fällen wäre es eine gute Idee, eine rvalue-Referenz zurückzugeben. Stellen Sie sich vor, Sie haben eine getAB()Funktion, die Sie häufig vorübergehend aufrufen. Es ist nicht optimal, eine konstante Wertreferenz für rwertige Provisorien zurückzugeben. Sie können es so implementieren

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

Beachten Sie, dass dies movein diesem Fall nicht optional ist, da abes sich weder um einen lokalen automatischen noch um einen temporären Wert handelt. Das ref-Qualifikationsmerkmal && besagt nun, dass die zweite Funktion für rvalue-Temporäre aufgerufen wird, wobei anstelle des Kopierens der folgende Schritt ausgeführt wird

Beta_ab ab = Beta().getAB();

51
Ich war immer davon ausgegangen, dass das baumelnde Referenzproblem automatisch verschwand, wenn der Rückgabetyp eine R-Wert-Referenz war. Ich bin froh, dass ich das klargestellt habe, bevor es mich gebissen hat. Stack Smashing Bugs saugen.
Deft_code

31
:) Wirklich, rWertreferenzen sind "nur Referenzen" wie lWertreferenzen. Sie kopieren oder speichern nichts.
Johannes Schaub - litb

9
Was funktioniert die Konstante & Qualifikation eines Mitglieds mehr als eine einfache Konstante?
Galinette


3
@galinette Dies sind Ref-Qualifikanten .
Malcolm

2

Es kann zum Beispiel in einem etwas anderen Kontext effizienter sein:

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;
}

Als interessante Beobachtung clang++ -O3generiert mein Computer 54 Anweisungen für den obigen Code gegenüber 62 Anweisungen für den regulären Code std::min. Damit werden jedoch -O0518 Anweisungen für den obigen Code generiert, gegenüber 481 für reguläre std::min.


Ihre Antwort verwirrt mich. Hatte eine ähnliche (vielleicht) Version ausprobiert, die jedoch fehlgeschlagen ist: ideone.com/4GyUbZ Können Sie erklären, warum?
Deqing

Sie haben die Referenz für ein temporäres Objekt in einem for(:)freigegebenen Objekt verwendet und dieses integriert. Fix: ideone.com/tQVOal
Wonder.mice

3
Ist diese Antwort nicht wirklich falsch? Für den Vorlagenparameter T ist T && keine r-Wert-Referenz, sondern eine universelle Referenz. In diesem Fall sollten wir immer std :: forward <T> aufrufen, nicht std :: move! Ganz zu schweigen davon, dass diese Antwort der oben genannten direkt widerspricht.
Xdavidliu

@xdavidliu Diese Antwort ist ein erfundenes Beispiel dafür, wie die Rückgabe per rvalue effizienter sein kann. std::move()wird nur als explizite Besetzung verwendet, um den Punkt klarer zu veranschaulichen. Es ist kein Code, den Sie kopieren und in Ihr Projekt einfügen würden. Dies widerspricht nicht der Antwort mit der höchsten Abstimmung, da dort ein temporäres Objekt innerhalb der Funktion erstellt wird. Hier ist das zurückgegebene Objekt eines der Argumente (temporäre Objekte werden als letzter Schritt bei der Bewertung des vollständigen Ausdrucks zerstört, der (lexikalisch) den Punkt enthält, an dem sie erstellt wurden).
Wonder.mice

2
@ Wonder.mice dann ersetze bitte T durch std :: string; Hier müssen überhaupt keine Vorlagen verwendet werden, und die Verwendung von T && als Referenz für R-Werte ist nur ein schrecklicher Stil, der Menschen, die mit Vorlagen und R-Werten noch nicht vertraut sind, unnötig verwirrt.
xdavidliu
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.