2009-05-09 10 views
20

Eines der coolen neuen Features des kommenden C++ - Standards, C++ 0x, sind "rvalue references". Eine rvalue Referenz ähnelt eine L-Wert (normal) Referenz, mit der Ausnahme, dass es in einem temporären Wert gebunden werden kann (in der Regel kann ein temporäre nur auf eine const Referenz gebunden werden):Warum sind C++ 0x rvalue Referenz nicht die Standardeinstellung?

void FunctionWithLValueRef(int& a) {...} 
void FunctionWithRValueRef(int&& a) {...} 

int main() { 
    FunctionWithLValueRef(5); // error, 5 is a temporary 
    FunctionWithRValueRef(5); // okay 
} 

Also, warum haben sie erfinden Sie einen ganz neuen Typ, anstatt nur die Einschränkungen für normale Referenzen zu entfernen, damit sie an Provisorien gebunden werden können?

+3

Ich frage mich, warum das 3 Stimmen bekam, aber 7 Favoriten. Ich glaube nicht, dass ich jemals eine Frage favorisiert habe, ohne sie abzustimmen (es sei denn, ich hatte keine Wahl oder war gesperrt). – Zifre

+3

Ich frage mich, warum jemand in irgendeiner Weise denkt und dann erwartet er, dass alle anderen genau das tun werden, was er tut. – user534498

+1

Ich frage mich, warum "nett zu sein und eine Aufwertung zu geben" eine unvernünftige Erwartung ist. –

Antwort

43

Es wäre sinnlos. Sie würden das Ding in der Funktion ändern, und die Änderung wäre sofort verloren, weil das Ding tatsächlich ein vorübergehendes war.

Der Grund für den neuen Typ ergibt sich aus der Notwendigkeit, entscheiden zu können, was eigentlich ein rvalue ist und was nicht. Nur dann können Sie sie tatsächlich für die coolen Dinge verwenden, die sie benutzen.

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

Nun, wenn Sie etwas rvalue haben und geben sie direkt an ToUpper kann der R-Wert verändert werden, weil wir die temporären ist eine Wegwerf-Sache sowieso wissen, so können wir aswell nur sie und don ändern‘ Ich muss es kopieren. Die gleiche Beobachtung wird auch für die Move-Konstruktoren und die Move-Zuweisung verwendet. Die rechte Seite wird nicht kopiert, aber ihre Sachen werden einfach weg gestohlen und zu *this verschoben.

Wenn Sie sagen würden, dass rvalues ​​an nicht konstante Lvalue-Referenzen binden können, dann hätten Sie keine Möglichkeit herauszufinden, ob diese am Ende auf einen lvalue (benanntes Objekt) oder einen rvalue (temporär) verweist.


Es ist wahrscheinlich wenig wissen, aber nützlich wie auch immer, können Sie lvalue oder rvalue ref-Qualifier auf eine Elementfunktion setzen. Hier ist ein Beispiel, die natürlich die bestehende Semantik rvalue Verweise auf den impliziten Objektparameter erweitert:

struct string { 
    string& operator=(string const& other) & { /* ... */ } 
}; 

Nun kann man nicht mehr sagen

string() = "hello"; 

die verwirrend ist und nicht wirklich machen Sinn die meiste Zeit. Was die obigen & sagt, ist, dass der Zuweisungsoperator nur für lvalues ​​aufgerufen werden kann. Das gleiche kann für rvalues ​​getan werden, indem && gesetzt wird.

+1

+1 Wow danke für den letzten Teil über den lvalues ​​/ rvalues ​​only member call!Ich habe viel über C++ 0x gelesen, habe aber nichts davon gesehen (ich denke, es ist im letzten Entwurf, aber ich habe nicht alles gelesen). Können Sie mich auf eine Dokumentation über diese Funktion hinweisen? – Klaim

+0

Hier ist ein schöner Überblick: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1821.htm. In dem Arbeitspapier, siehe 8.3.5, 9.3.1 und 13.3.1. –

+0

Danke für diese Antwort, das macht es viel klarer. Ich habe die rvalue-Referenzen nicht wirklich verstanden. Das macht viel mehr Sinn als das, was ich dachte. – Zifre

12

Da eine neue Art von Referenz Hinzufügen Sie ermöglicht es, zwei Überlastungen eines Verfahrens zu 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 isn Ich werde nirgendwo sonst benutzt. So kann es den Inhalt davon "stehlen".

Dies ist der Grund, warum diese Funktion hinzugefügt wurde; die Beibehaltung eines Referenztyps würde das gewünschte Ziel nicht erreichen.