Warum sind C++0x-Wertreferenzen nicht die Standardeinstellung?
Frage
Eine der coolen neuen Funktionen des kommenden C ++ - Standards C ++ 0x sind "RValue -Referenzen". Eine RValue -Referenz ähnelt einer lvalue (normalen) Referenz, mit der Ausnahme, dass sie an einen temporären Wert gebunden werden kann const
Referenz):
void FunctionWithLValueRef(int& a) {...}
void FunctionWithRValueRef(int&& a) {...}
int main() {
FunctionWithLValueRef(5); // error, 5 is a temporary
FunctionWithRValueRef(5); // okay
}
Warum haben sie also einen völlig neuen Typ erfunden, anstatt einfach die Einschränkungen für normale Referenzen aufzuheben, um die Bindung an Provisorien zu ermöglichen?
Lösung
Es wäre sinnlos.Sie würden das Ding in der Funktion ändern und die Änderung würde sofort verloren gehen, da das Ding eigentlich nur vorübergehend ist.
Der Grund für den neuen Typ liegt in der Notwendigkeit, entscheiden zu können, was tatsächlich ein R-Wert ist und was nicht.Nur dann kann man sie tatsächlich für die coolen Dinge verwenden, für die sie verwendet werden.
string toupper(string && s) { // for nonconst rvalues
for(char &c : s) make_uppercase(c);
return move(s); // move s into a returned string object
}
string toupper(string const& s) { // for the rest
// calls the rvalue reference version, by passing
// an rvalue copy.
return toupper(string(s));
}
Wenn Sie nun einen R-Wert haben und ihn an toupper übergeben, kann der R-Wert direkt geändert werden, da wir wissen, dass der temporäre Wert sowieso wegwerfbar ist, sodass wir ihn auch einfach ändern können und ihn nicht kopieren müssen.Dieselbe Beobachtung wird auch für die sogenannten Bewegungskonstruktoren und Bewegungszuweisungen verwendet.Die rechte Seite wird nicht kopiert, sondern ihre Sachen werden einfach gestohlen und dorthin verschoben *this
.
Wenn Sie sagen würden, dass R-Werte an nicht konstante L-Wert-Referenzen binden können, dann hätten Sie keine Möglichkeit herauszufinden, ob dies letztendlich auf einen L-Wert (benanntes Objekt) oder einen R-Wert (temporär) verweist.
Es ist wahrscheinlich weniger bekannt, aber trotzdem nützlich: Sie können L-Wert- oder R-Wert-Ref-Qualifizierer in eine Mitgliedsfunktion einfügen.Hier ist ein Beispiel, das die bestehende Semantik von R-Wert-Referenzen natürlich auf den impliziten Objektparameter erweitert:
struct string {
string& operator=(string const& other) & { /* ... */ }
};
Jetzt kann man es nicht mehr sagen
string() = "hello";
Was verwirrend ist und meistens keinen Sinn ergibt.Was zum &
Das Obige besagt, dass der Zuweisungsoperator nur für L-Werte aufgerufen werden kann.Dasselbe kann für R-Werte durch Setzen erfolgen &&
.
Andere Tipps
Da eine neue Art von Referenz Hinzufügen können Sie zwei Überlastungen eines Verfahrens schreiben:
void CopyFrom(MyClass &&c)
{
dataMember.swap(c);
}
void CopyFrom(const MyClass &c)
{
dataMember.copyTheHardWay(c);
}
Die Version, die die neue Art Referenz akzeptiert darf die Variable ändern sie erhält, weil diese Variable nicht anderswo verwendet werden soll. So kann es „stehlen“ den Inhalt davon.
Das ist der ganze Grund, warum diese Funktion hinzugefügt wurde; eine Art von Referenz beibehalten würde das angestrebte Ziel nicht erreichen.