GCC 3.4 Optimierungswunder??
-
Hi Leute!
Ich arbeite mich gerade durchs Buch OOP für Dummies. Nun wird über Rückgabe lokaler Objekte aus einer Funktion diskutiert (Kapitel 11 S. 215ff.). Es herscht eine einfache Ausgangslage mit dieser Klasse:
class XXX { public: XXX(); XXX(int value); XXX(const XXX& source); const XXX& operator=(const XXX& source); int getValue() const {return m_Value;} void setValue(int value) {m_Value = value;} private: int m_Value; }; XXX::XXX() : m_Value(0) { cout << "Defaultkonstruktor" << endl; } XXX::XXX(int value) : m_Value(value) { cout << "int-Konstruktor" << endl; } XXX::XXX(const XXX& source) : m_Value(source.m_Value) { cout << "Copykonstruktor" << endl; } const XXX& XXX::operator=(const XXX& source) { m_Value = source.m_Value; cout << "Operator =" << endl; return *this; }
und diesem Aufruf:
XXX getX1() { XXX x1(1); cout << x1.getValue() << endl; return x1; } const XXX getX2() { XXX x2(2); cout << x2.getValue() << endl; return x2; } int main() { XXX x1, x2; cout << "x1" << endl; x1 = getX1(); cout << "x2" << endl; x2 = getX2(); cout << x1.getValue() << endl; cout << x2.getValue() << endl; getX1().setValue(5); // getX2().setValue(5); XXX x3 = getX1(); return 0; }
Nun der erwartete Output laut Buch:
Defaultkonstruktor Defaultkonstruktor x1 int-Konstruktor 1 Copykonstruktor Operator = x2 int-Konstruktor 2 Copykonstruktor Operator = 1 2 int-Konstruktor 1 int-Konstruktor 1 Copykonstruktor
Als ich nun aber das Ganze mit GCC 3.4 kompiliert habe gibts als Output keinen einzigen Copykonstruktor-Aufruf, optimiert etwa der Compiler die schon alle weg??
Das wäre ja noch gut, aber ein Aufruf wie
x1 = getX1().setValue( 666 );
funktioniert leider auch nicht!
Dabei sollte das doch gehen, oder nicht??
-
DanEE schrieb:
Als ich nun aber das Ganze mit GCC 3.4 kompiliert habe gibts als Output keinen einzigen Copykonstruktor-Aufruf, optimiert etwa der Compiler die schon alle weg??
Ja, das nennt sich NRVO (Named Return Value Optimization) und wird von neueren Compilern hoffentlich weitgehend unterstützt. AFAIK ist das auch die einzige Optimierung, die Compiler machen dürfen, die die Semantik des Programmes verändert.
siehe Hume's FAQ: http://fara.cs.uni-potsdam.de/~kaufmann/?page=GenCppFaqs&faq=Optimize#Answ
Das wäre ja noch gut, aber ein Aufruf wie
x1 = getX1().setValue( 666 );
funktioniert leider auch nicht!
Natürlich nicht. setValue hat keinen Rückgabewert (wg. void). Da müsste der Compiler schon streiken.
-
Das ist nicht weiter verwunderlich. Warum soll der Compiler für etwas Code generieren, das eh nicht mehr gebraucht wird? Compiliere das ganze im Debug Mode oder gib die veränderten Werte zB mit cout auf der Konsole aus.
-
Bashar schrieb:
Das wäre ja noch gut, aber ein Aufruf wie
x1 = getX1().setValue( 666 );
funktioniert leider auch nicht!
Natürlich nicht. setValue hat keinen Rückgabewert (wg. void). Da müsste der Compiler schon streiken.
Logisch, ich weiss nicht was ich da überlegt habe.
Ich war über den fehlenden Copykonstruktor verwirrt, aber eigentlich macht es schon Sinn, dass er den wegoptimiert...
-
Wieso macht das Sinn? Wird x1 danach nciht mehr verwendet, oder wieso?
-
x1 wird schon noch verwendet, aber nicht mehr die temporäre Instanz von XXX die GetX1 zurückgibt (und laut dem Buch die Ursache für den Copykonstruktor ist).
Falls ich das richtig verstanden habe, kann der Compiler es deshalb wegoptimieren.Wenn ich nun
void setValue(int value) {m_Value = value;}
durch
XXX setValue(int value) {m_Value = value; return *this;}
ersetze, forciere ich mit der Zeile
x1 = getX1().setValue( 666 );
in der Tat einen Copykonstruktoraufruf.
Der Compiler ist also gar nicht so dumm, zumindest klüger als ich :p
@Bashar: Danke übrigens für den Link zur FAQ
-
dEUs: Doch schon, aber die Funktion konstruiert ihren Rückgabewert nicht erst in ihrem eigenen Stackframe, sondern gleich an der Stelle von x1, so dass er nicht kopiert werden muss.