C++: Rückgabe-Wert einem L-Wert?
Betrachten Sie diesen code:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
Kein compiler beschwert sich darüber, auch das Geräusch. Warum q() = ...
Zeile korrekt ist?
- Wow, gute Frage, +1.
- Was denkst du, ist falsch an diesem code?
q()
gibt einen struct und dann weisen Sie einen Wert zu. Was ist falsch mit, dass? - Carnegie: Guter Kommentar!
- Ich denke, dass es sehr fehleranfällig ist, da die Zuordnung Wert, der zurückgegeben Wert in der Regel nichts (außer, wenn operator= macht eine Magie, die wohl schlechte design-Praxis). Ich habe erwartet, dass dies eine Warnung sein, wie nicht mit lokalen Variablen.
- Johnson: Das weit verbreitete Missverständnis ist, dass Menschen davon ausgehen, dass alles, was Sie können auf der linken Seite der Zuweisung muss ein lvalue. In diesem Fall ist diese Anforderung scheint zu sein, verletzt. Aber in Wirklichkeit gibt es keine solche Vorschrift. Built-in Zuordnung erfordert in der Tat und lvalue auf seine LS, aber überlastet Zuweisung nicht. In diesem Fall haben wir es mit dem überladen, auch wenn es nicht offensichtlich ist.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nein, der Rückgabewert einer Funktion ist ein l-Wert, wenn und nur wenn es eine Referenz (C++03). (5.2.2 [expr.call] /10)
Wenn der Typ zurückgegeben wurden, eine grundlegende Art, dann wäre dies ein compile-Fehler. (5.17 [expr.ass] /1)
Dem Grund, dass dies funktioniert, ist, dass Sie erlaubt sind zu nennen member-Funktionen (auch nicht-
const
member-Funktionen) auf r-Werte von Klasse-Typ und die Zuweisung derfoo
ist eine Implementierung der member-Funktion definiert:foo& foo::operator=(const foo&)
. Die Einschränkungen für Operatoren in Ziffer 5 gelten nur für built-in Operatoren, (5 [expr] /3), wenn überlast Auflösung wählt einen überladenen Funktionsaufruf-operators dann die Einschränkungen für diese Funktion aufrufen, gelten anstelle.Dies ist, warum es wird manchmal empfohlen, um Rendite-Objekte Klasse Typ wie
const
Objekte (z.B.const foo q();
), dies kann jedoch eine negative Auswirkung in C++0x, wo es hemmt move-Semantik von arbeiten, wie Sie sollten.std::cout << "Hello, world" << std::endl
. Die erstenoperator<< ()
gibt einen lvalue, auf dem Sie anrufen können, der zweiteoperator<< ()
. Also diese Praxis der aufrufen von Methoden, die Werte zurückgeben, ist weiter verbreitet als viele Menschen denken würde.The Design and Evolution of C++
: Dies ist der Ursprung der Vorstellung, dass im Laufe der Jahre wuchs in einer Faustregel zum design von C++: benutzerdefinierte und eingebaute Typen Verhalten sollen, die gleichen, die relativ zu der Sprache, die Regeln und erhalten den gleichen Grad an Unterstützung durch die Sprache und die zugehörigen tools. Wenn das ideal wurde formuliert, built-in-Typen erhielt mit Abstand die beste Unterstützung, aber C++ hat das Ziel hinausgeschossen, so dass die built-in-Typen erhalten jetzt geringfügig schlechter support im Vergleich zu user-defined types.cout
es tatsächlich kehren Sie ein lvalue (es gibt selbst und die durch Verweis*this
), nicht etwas von Wert. So ist es ein wenig anders.std::cout << "duh" << std::endl
, dieoperator<<
alle wieder nicht-const-Referenzen (das sind lvalues), und da die Betreiber eine nicht-const-Referenzen als ersten parameter, den ursprünglichenstd::ostream
- Objekt kann nicht in ein rvalue. In den anderen Beispielen (und ich nehme an, dies ist die motivation nicht in Frage), nicht-const-Funktionen aufgerufen werden, die auf eine vorübergehende.q().operator=(i)
ist nicht wirklich außergewöhnlich.Da Strukturen zugeordnet werden können, und Ihre
q()
gibt eine Kopiestruct foo
so seine Zuordnung der zurückgegebenen struct den Wert zur Verfügung gestellt.Dies ist nicht wirklich etwas tun in diesem Fall Gedanken, weil das struct außerhalb des gültigen Bereichs hinterher und Sie nicht halten Sie einen Verweis, um es in den ersten Platz, so dass Sie nicht tun konnte, was er sowieso (in diesem spezifischen code).
Das macht mehr Sinn (wenn auch noch nicht wirklich ein "best practice")
int blah() { int f = 4; return f; } int main() { int a = 99; blah() = a; }
ist es etwas Magisches an Strukturen? Weil dieser code nicht kompilieren.int::operator=(int)
entweder. Das ist die "Magische" etwas über Strukturen: haben Sie Standard-Methoden.s/nothing/anything/
Eine interessante Anwendung dieser:
Hier
g() +=
ändert die temporäre, die möglicherweise schneller sein, dass die Erzeugung eines zusätzlichen temporären mit+
da der heap reserviert für g()'s Rückgabewert haben vielleicht schon genug freie Kapazitäten, um Platz für</tag>
.Sehen, es laufen bei ideone.com mit GCC /C++11.
Nun, die computing-Neuling sagte etwas über Optimierungen und böse...? ;-].