Gibt es einen Grund, warum eine Funktion eine RValue-Referenz zurückgeben sollte ? Eine Technik oder ein Trick oder eine Redewendung oder ein Muster?
MyClass&& func( ... );
Ich bin mir der Gefahr bewusst, Referenzen im Allgemeinen zurückzugeben, aber manchmal tun wir es trotzdem, nicht wahr? T& T::operator=(T)
ist nur ein idiomatisches Beispiel. Aber wie wäre es T&& func(...)
? Gibt es einen allgemeinen Ort, an dem wir davon profitieren würden? Wahrscheinlich anders, wenn man Bibliotheks- oder API-Code schreibt, als nur Client-Code?
value_type
stattvalue_type&&
als Rückgabetyp?const X& x = *i
ist ziemlich selten. Ich glaube nicht, dass ich es jemals gesehen habe.Dies folgt auf Towis Kommentar. Sie möchten niemals Verweise auf lokale Variablen zurückgeben. Aber Sie könnten dies haben:
vector<N> operator+(const vector<N>& x1, const vector<N>& x2) { vector<N> x3 = x1; x3 += x2; return x3; } vector<N>&& operator+(const vector<N>& x1, vector<N>&& x2) { x2 += x1; return std::move(x2); } vector<N>&& operator+(vector<N>&& x1, const vector<N>& x2) { x1 += x2; return std::move(x1); } vector<N>&& operator+(vector<N>&& x1, vector<N>&& x2) { x1 += x2; return std::move(x1); }
Dies sollte in allen Fällen Kopien (und mögliche Zuordnungen) verhindern, außer wenn beide Parameter l-Werte sind.
quelle
return std::move(x2);
usw. Oder Sie könnten eine Umwandlung in den Referenztyp rvalue schreiben, aber genau dasmove
tut es trotzdem.Geben Sie einfach den Wert zurück. Das Zurückgeben von Referenzen im Allgemeinen ist überhaupt nicht gefährlich - es gibt Referenzen auf lokale Variablen zurück, was gefährlich ist. Die Rückgabe einer Wertreferenz ist jedoch in fast allen Situationen ziemlich wertlos (ich denke, wenn Sie geschrieben haben
std::move
oder so).quelle
T&& operator+(const T&,T&&)
sollten&&
. Aber das ist jetzt im endgültigen Entwurf weg. Deshalb frage ich.Sie können als Referenz zurückkehren, wenn Sie sicher sind, dass das referenzierte Objekt nach dem Beenden der Funktion nicht den Gültigkeitsbereich verlässt, z. B. die Referenz eines globalen Objekts oder die Mitgliedsfunktion, die die Referenz auf Klassenfelder usw. zurückgibt.
Diese Rückgabereferenzregel ist sowohl für die l-Wert- als auch für die r-Wert-Referenz identisch. Der Unterschied besteht darin, wie Sie die zurückgegebene Referenz verwenden möchten. Wie ich sehen kann, ist die Rückkehr per rWert-Referenz selten. Wenn Sie Funktion haben:
Type&& func();
Sie werden solchen Code nicht mögen:
weil es ref_a effektiv als Typ definiert & da die benannte rWertreferenz ein lWert ist und hier keine tatsächliche Verschiebung durchgeführt wird. Es ist ganz wie:
const Type& ref_a = func();
mit der Ausnahme, dass die tatsächliche ref_a eine nicht konstante Wertreferenz ist.
Und es ist auch nicht sehr nützlich, selbst wenn Sie func () direkt an eine andere Funktion übergeben, die ein Type &&-Argument akzeptiert, da es sich immer noch um eine benannte Referenz innerhalb dieser Funktion handelt.
void anotherFunc(Type&& t) { // t is a named reference } anotherFunc(func());
Die Beziehung zwischen func () und anotherFunc () ähnelt eher einer "Autorisierung", der func () zustimmt, dass anotherFunc () möglicherweise das zurückgegebene Objekt von func () übernimmt (oder Sie können sagen "stehlen"). Diese Vereinbarung ist jedoch sehr locker. Eine nicht konstante Wertreferenz kann weiterhin von Anrufern "gestohlen" werden. Tatsächlich werden Funktionen selten definiert, um rvalue-Referenzargumente zu verwenden. Der häufigste Fall ist, dass "anotherFunc" ein Klassenname ist und anotherFunc () tatsächlich ein Verschiebungskonstruktor ist.
quelle
Ein weiterer möglicher Fall: Wenn Sie ein Tupel entpacken und die Werte an eine Funktion übergeben müssen.
Dies kann in diesem Fall hilfreich sein, wenn Sie sich bei der Kopierentfernung nicht sicher sind.
Ein solches Beispiel:
template<typename ... Args> class store_args{ public: std::tuple<Args...> args; template<typename Functor, size_t ... Indices> decltype(auto) apply_helper(Functor &&f, std::integer_sequence<size_t, Indices...>&&){ return std::move(f(std::forward<Args>(std::get<Indices>(args))...)); } template<typename Functor> auto apply(Functor &&f){ return apply_helper(std::move(f), std::make_index_sequence<sizeof...(Args)>{}); } };
Ziemlich seltener Fall, es sei denn, Sie schreiben irgendeine Form
std::bind
oderstd::thread
Ersatz.quelle