Konstruktor im Return-Statement funktioniert nicht (Codebeispiel)
-
Hallo,
Ich habe das Problem, dass zurückgegebene Objekte bei verschachtelten Aufrufen scheinbar ihre Gültigkeit verlieren. Im folgenden ein Codebeispiel (ich habe den ursprünglichen nicht funktionierenden Code sehr gekürzt und zusammengefasst - ich habe alles gelöscht, was mit dem Problem nichts zu tun hat und alle Klassenelemente public deklariert - so ist der Code nun einfacher zu lesen, wenn auch kein sauberer C++-Code mehr):
Eine Klasse 'zahl' beinhaltet ein double-Feld 'wert' und zwei Operatoren +=,*= :
#ifndef __GLEICHUNGEN__ZAHL_H__ #define __GLEICHUNGEN__ZAHL_H__ class zahl { public: zahl(double value):wert(value) {} double wert; //Rechenoperatoren zahl &operator+=(const zahl &rvalue); zahl &operator*=(const zahl &rvalue); }; inline zahl &zahl::operator+=(const zahl &rvalue) { wert+=rvalue.wert; return *this; } inline zahl &zahl::operator*=(const zahl &rvalue) { wert*=rvalue.wert; return *this; } #endifmain: Die Funktion main() definiert 3 Instanzen der Klasse zahl und will z1*(z2+z3) mittels der +=,*= - Operatoren ausrechnen.
#include <iostream> #include "zahl.h" using std::cout; const zahl &addition(zahl *_links,zahl *_rechts) { return zahl(_links->wert)+=*_rechts; } const zahl &f1(zahl *z1,zahl *z2,zahl *z3) { return zahl(z1->wert)*=addition(z2,z3); } int main() { zahl z1(3),z2(5),z3(6); //z1*(z2+z3) std::cout << f1(&z1,&z2,&z3).wert; }Leider erhalte ich nicht das erwartete Ergebnis 3*(5+6)=33, sondern das Programm gibt eine Zahl mit einer Zehnerpotenz von etwa -300 aus. Vermutlich werden die in den Funktionen f1 bzw addition zurückgegebenen Objekte ungültig.
Wenn ich bei den Konstruktoren in zB f1() das = wegnehme und nur zahl(z1->wert) zurückgebe, gibt der Compiler einen Fehler aus, dass ein temporäres Objekt zurückgegeben wird. Wieso funktioniert das ganze dann mit dem Operator=?
Und warum funktioniert es nicht? Ich habe mal gelesen, dass man bei Funktionen, welche Objekte zurückgeben, const-Referenzen als Rückgabewert und einen Konstruktor als return-Statement nehmen soll. War das eine Falschinformation?Gruß,
Heinzi
-
Da hast du Unsinn gelesen. Die zurückgegebenen Referenzen verweisen auf Objekte, die nach dem Ende der Funktion sofort zerstört werden - und damit naturgemäß auf undefinierte Speicherbereiche. Übrigens ist es unsinnig, deine Objekte per Zeiger an die Funktionen zu übergeben.
(da ist es besser, neben den bisherigen Operatoren auch + und * zu überladen - dann brauchst du deine Funktionen überhaupt nicht mehr:
zahl operator +(zahl r, zahl l) { return r+=l; } zahl operator *(zahl r, zahl l) { return r*=l; } ... cout<<z1*(z2+z3)<<endl;
-
Hallo,
das Beispiel ist nur Unsinn, weil ich es so gekürzt habe. Die Zeiger brauche ich, da es im eigentlichen Programm Zeiger auf eine Basisklasse sind. Ich habe im Programm auch die Operatoren +,* definiert, welche folgendermaßen aussehen:
template<class T> const T operator+(const T& lhsObj,const T& rhsObj) { return T(lhsObj) += rhsObj; //return von Konstruktor }Dieses Codebeispiel ist aus "Notizen zu C++" von Peter Thömmes (Version: 09. August 2003) Seite 196/197: http://www.astro.uni-wuerzburg.de/~asmaier/usefulthings/c++.pdf
Hier funktioniert es mit der Rückgabe der Referenzen. Soweit ich weiß, heißt die Technik return value optimization und ist eine Compilererweiterung, welche dafür sorgt, dass in Funktionen, welche lokale Objekte zurückgeben müssen, diese nicht zuerst in der Funktion und dann nochmal bei der Rückgabe neu konstruiert werden.
Da ich mit dem GCC compiliere und dieser die entsprechende Compilererweiterung normalerweise hat, dürfte es kein Problem geben.
Das Problem entsteht irgendwie erst, wenn ich die zurückgegebenen Objekte gleich weiter an Funktionen übergebe.Gruß,
Heinzi
-
Mal ganz platt gefragt: Wo siehst Du in dem Codebeispiel die Rückgabe von Referenzen? Hier wird by-value zurückgegeben. Genau das musst Du in Deinem Code auch tun.
-
Ich depp - du hast recht...da wird ja tatsächlich by value zurückgegeben...das habe ich irgendwie übersehen.
Funktioniert die return value optimization also, wenn ich ein Objekt by value zurückgebe?Gruß,
Heinzi