return reference
-
-
foogard schrieb:
aber mir kamm schon der gedanke, wie man so einen von maria_69 geschildeten fall am besten umgeht. evtl static verwenden?
Kommt halt auf den jeweiligen Fall an.
statickann verwendet werden, wenn ein Objekt bis zum Programmende bestehen soll. Im Normalfall gibt man aber eine Kopie des Objekts zurück.
-
Eine Variable als 'static' zu deklarieren ist nur sinnvoll, wenn Du den Inhalt dieser Variablen beim erneuten Aufruf der Funktion wieder brauchst. Das ist meist ein Ausnahmefall, z.B. wenn Du zählen möchtest, wie oft eine Funktion während des Programmablaufes ausgeführt wird. Ich glaube nicht, das dieses Verhalten von Dir an dieser Stelle gebraucht wird.
Ein Objekt als Referenz zurückzugeben funktioniert, wenn genau dieses Objekt als Referenz an die Funktion übergeben wurde oder wenn ein Objekt dynamisch angelegt und nicht wieder zerstört wurde. In allen anderen Fällen ist die Rückgabe als Kopie der richtige Weg.
-
static solltest du dafür auf keinen Fall benutzen! Es ist hier z.B. für den Nutzer des Interfaces nicht ersichtlich, dass sowas hier nur crap ergibt:
const std::string& clone( const char* blubb ) { static std::string s; s = blubb; return s; } std::string potentially_bug = clone("hello") + clone("world"); // Sollte "hellohello" oder "worldworld" ergeben.
-
mario_69 schrieb:
Ein Objekt als Referenz zurückzugeben funktioniert, wenn genau dieses Objekt als Referenz an die Funktion übergeben wurde oder wenn ein Objekt dynamisch angelegt und nicht wieder zerstört wurde. In allen anderen Fällen ist die Rückgabe als Kopie der richtige Weg.
Den Fall mit dem dynamisch angelegten Objekt würde ich auch rausnehmen. Speicherlecks können auch den Tod eines Programms verursachen. Dauert eben nur länger.
Grundsätzlich würde ich es wie Nexus machen. Rückgabe per Wert und dem Compiler vertrauen, dass er die Funktion automatisch umwandelt.
-
@ foogard:
Das ist ja noch schlimmer, als eine stack-Variable zurück zu geben.
Weil:
das Kompiliert der Kompiler höchstwahrscheinlich ohne fehlermeldung.
man stelle sich aber folgenden Anwendungsfall vor:TolleKlasse& superdummeFunktion(Parameter poar1, Parameter par2) { static TolleKlasse dummIdee; ... return dummIdee; } void unschuldierBenutzer() { TolleKlasse& a = superdummeFunktion('s', 324622) ...schwierige Berechnungen .. TolleKlasse& b = superdummeFunktion( ergbniss_der_schwierigen_Berechnung_1, ergbniss_der_schwierigen_Berechnung_2); vegleiche(a, b); }Na? Ahnst dus?
Ganz zu schweigen davon, was passiert, wenn man Threads benutzt -.-Edit:
Darüber sollte man sich auch nur untergeordnet Gedanken machen.
Die modernen Kompiler können 'return value optimaization'.
Das heißt intern übergeben sie den speicher, der eigendlich der Rückgabewert ist, an die Funktion, so dass die Erzeugung und die Kopie des Rückgabeobjektes vermieden wird.Edit:
In dem Buch von Scott Meyers (More?) Effective C++
Da gibts auch ein Kapitel über diese Problematik und die hier diskutierten Lösungsvorschläge.
-
Nexus schrieb:
drakon schrieb:
Wegen Zeitoptimierung ist es sicher zu früh, um zu schauen. Ich würde empfehlen das zu nehmen, was eher Sinn macht. (Wahrscheinlich ist das die Rückgabe einer Kopie).
Das würde ich jetzt aber bestimmt nicht unter Mikrooptimierung zählen. Wenn man wirklich den gesamten Container zurückgeben will (ist eine Designfrage, die kürzlich hier besprochen wurde), ist ein reiner Lesezugriff wahrscheinlicher. Eine Kopie kann zeitaufwändig werden. Wenn man trotzdem eine Kopie braucht, kann man es ja immer noch wie von vlad_tepesch beschrieben tun.
Er macht sich hier zuerst Gedanken, was schneller ist, als zuerst zu schauen, für was er das braucht und das ist unsinnig. Die Rückgabe einer nicht-const-Referez auf eine private Member macht für mich einfach überhaupt keinen Sinn. Da kann ich den auch gleich public machen. Die Rückgabe einer const-Referenz auf eine private Member kann hingegen Sinn machen, da man durchaus lesend darauf zugreifen soll, jedoch schreibend durch eine Funktion.
Ob man es jetzt dem Programmier überlässt, ob eine Kopier erstellt werden soll, oder nicht (mittels const-Referenz) ist abhängig vom Kontext, wie die Funktion gebraucht wird. Wenn direkt weitergearbeitet werden soll, macht eine Kopie sicher Sinn (Operatorenüberladung).
-
die rückgabe einer nicht konstreferenze macht dann, sinn, wenn du das interface, von der implementierung unabhängig machen willst, aber nicht tausend getter und setter schreiben willst, weil das unhantlich ist.
Hatte das Beispiel schon mal ähnlich gepostet:
tepmplate<class t> class Vector3: { public: T x()const { return m_vec[0];} T y()const { return m_vec[1];} T z()const { return m_vec[2];} T& x() { return m_vec[0];} T& y() { return m_vec[1];} T& z() { return m_vec[2];} private: T m_vals[3] }Bei so elementaren Klassen ist das handling mit setter und getter meist recht unschön
-
vlad_tepesch, bei dir kann man aber geradesogut die Member öffentlich machen. Sind die Aufrufe der Methoden überhaupt immer eindeutig?
-
Nexus schrieb:
vlad_tepesch, bei dir kann man aber geradesogut die Member öffentlich machen. Sind die Aufrufe der Methoden überhaupt immer eindeutig?
Die aufrudfe sind eindeutig.
wenn ich mein member öffentlich mache, habe ich keine x,y,z komponenten, sondern nur noch ein array, was ich nicht möchte.
Außerdem vielleicht ändert sich die interne struktur irgendwann mal, dann muss man den ganzen bisher geschriebenen Code umbuaen.
So muss man nur die zugriffsfunktionen neu bauen.Di obige Variante kommt den c# propertys am nächsten. der einzige unterscihed sind die ellipsen
-
Okay, das mit der internen Struktur hat was.
Es kommt auch drauf an, wie man den Vektor verwendet. Wenn man seine Koordinaten bereits zu Beginn setzt und ihn nachher hauptsächlich mit den Operatoren manipuliert, sehe ich auch keinen grossen Sinn darin, einzelne Komponenten nachträglich zu verändern. Funktionen à la
SetX()undGetY()finde ich also je nach Anwendung gar nicht so schlecht...