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 Clang. Warum ist die q() = ...
Zeile korrekt?
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 Clang. Warum ist die q() = ...
Zeile korrekt?
q()
Gibt eine Struktur zurück und weist ihr dann einen Wert zu. Was stimmt damit nicht?
Antworten:
Nein, der Rückgabewert einer Funktion ist genau dann ein l-Wert, wenn es sich um eine Referenz handelt (C ++ 03). (5.2.2 [Ausdruck] / 10)
Wenn der zurückgegebene Typ ein Basistyp wäre, wäre dies ein Kompilierungsfehler. (5,17 [Ausdruck] / 1)
Der Grund dafür ist, dass Sie Elementfunktionen (auch Nicht-Elementfunktionen const
) für r-Werte des Klassentyps aufrufen dürfen und die Zuweisung von foo
eine implementierungsdefinierte Elementfunktion ist : foo& foo::operator=(const foo&)
. Die Einschränkungen für Operatoren in Abschnitt 5 gelten nur für integrierte Operatoren (5 [Ausdruck] / 3). Wenn die Überlastauflösung einen überladenen Funktionsaufruf für einen Operator auswählt, gelten stattdessen die Einschränkungen für diesen Funktionsaufruf.
Aus diesem Grund wird manchmal empfohlen, Objekte vom Klassentyp als const
Objekte zurückzugeben (z. B. const foo q();
). Dies kann sich jedoch negativ auf C ++ 0x auswirken, da die Verschiebungssemantik möglicherweise nicht ordnungsgemäß funktioniert.
std::cout << "Hello, world" << std::endl
. Der erste operator<< ()
gibt einen Wert zurück, für den Sie den zweiten aufrufen können operator<< ()
. Daher ist diese Praxis, Methoden für Rückgabewerte aufzurufen, häufiger als viele Leute denken.
The Design and Evolution of C++
: Dies ist der Ursprung der Vorstellung, dass im Laufe der Jahre eine Faustregel für das Design von C ++ wurde: Benutzerdefinierte und integrierte Typen sollten sich im Verhältnis zu den Sprachregeln gleich verhalten und empfangen das gleiche Maß an Unterstützung durch die Sprache und die dazugehörigen Tools. Als das Ideal formuliert wurde, erhielten integrierte Typen bei weitem die beste Unterstützung, aber C ++ hat dieses Ziel überschritten, sodass integrierte Typen jetzt im Vergleich zu benutzerdefinierten Typen eine etwas schlechtere Unterstützung erhalten.
cout
es tatsächlich einen l-Wert zurück (es gibt sich selbst und als Referenz zurück *this
), nicht etwas nach Wert. Es ist also ein bisschen anders.
std::cout << "duh" << std::endl
den operator<<
alle Rückkehr nicht konstanten Referenzen (die L - Werte) sind, und weil die Betreiber all nicht konstante Referenzen als erste Parameter erfordern, das Original std::ostream
kann Objekt nicht ein R - Wert sein. In den anderen Beispielen (und ich nehme an, dass dies die Motivation der Frage ist) werden nicht konstante Funktionen vorübergehend aufgerufen.
Da Strukturen zugewiesen werden können und Sie q()
eine Kopie davon zurückgeben struct foo
, wird die zurückgegebene Struktur dem angegebenen Wert zugewiesen .
Dies macht in diesem Fall eigentlich nichts, weil die Struktur danach nicht mehr in den Geltungsbereich fällt und Sie überhaupt keinen Verweis darauf behalten, sodass Sie sowieso nichts damit anfangen können (in diesem speziellen Code).
Dies ist sinnvoller (obwohl immer noch keine "Best Practice")
struct foo
{
int a;
};
foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }
int main()
{
foo i;
i.a = 5;
//sets the contents of the newly created foo
//to the contents of your i variable
(*(q())) = i;
}
int blah() { int f = 4; return f; } int main() { int a = 99; blah() = a; }
Ist es etwas Magisches an Strukturen? Weil dieser Code nicht kompiliert wird.
int::operator=(int)
. Das ist das "magische" an Strukturen: Sie haben Standardmethoden.
s/nothing/anything/
Eine interessante Anwendung davon:
void f(const std::string& x);
std::string g() { return "<tag>"; }
...
f(g() += "</tag>");
Hier wird g() +=
das temporäre Element geändert, was möglicherweise schneller ist als das Erstellen eines zusätzlichen temporären Datenträgers, +
da der für den Rückgabewert von g () zugewiesene Heap möglicherweise bereits über genügend freie Kapazität verfügt </tag>
.
Sehen Sie es auf ideone.com mit GCC / C ++ 11 .
Welcher Computeranfänger sagte etwas über Optimierungen und das Böse ...? ; -].