lokaler shared pointer als return wert, geht das???
-
Hallo,
welche der beiden folgenden Funktionen ist unsinnig, oder sind beide unsinn?
boost::shared_ptr< std::vector< double > >Test::testFunction1() { boost::shared_ptr< std::vector< double > > values(new std::vector< double >(100)); std::vector< double > & ref = *values; for (int i=0; i<100; ++i) { ref[i]=double(i); } return boost::shared_ptr< std::vector< double > > (values); } boost::shared_ptr< std::vector< double > >Test::testFunction2() { boost::shared_ptr< std::vector< double > > values(new std::vector< double >(100)); std::vector< double > & ref = *values; for (int i=0; i<100; ++i) { ref[i]=double(i); } return values; }
====================================================
Ich habe beide Funktionen getestet und sie liefern genau das selbe Ergebniss.
====================================================
int main() { Test testObj; boost::shared_ptr< std::vector< double > > shareTestObj1, shareTestObj2; shareTestObj1 = testObj.testFunction1(); shareTestObj2 = testObj.testFunction2(); cout << "shareTestObj1 at(49):" << shareTestObj1->at(49) << endl; cout << "shareTestObj1 size:" << shareTestObj1->size() << endl; cout << "shareTestObj use_count():" << shareTestObj1.use_count() << endl; cout << "shareTestObj2 at(49):" << shareTestObj2->at(49) << endl; cout << "shareTestObj2 size:" << shareTestObj2->size() << endl; cout << "shareTestObj2 use_count():" << shareTestObj2.use_count() << endl; }
==========================
Das Ergebniss war:
shareTestObj1 at(49):49
shareTestObj1 size:100
shareTestObj use_count():1
shareTestObj2 at(49):49
shareTestObj2 size:100
shareTestObj2 use_count():1Ich habe das auch mit lokalen Variablen für Integer oder String probiert und sie werden alle richtig wiedergegeben.
In Scott Meyers Buch "Effektiv C++ programmieren" steht aber unter Tipp 21, zu Rückgabe von lokalen Variablen:
"ein ernsteres Problem besteht darin, dass die Funktion einen Verweis auf ein lokales Objekt zurückgibt und lokale Objekte zerstört werden, wenn die Funktion verlassen wird. ... Jede aufrufende Funktion , die auch nur auf den Rückgabewert dieser Funktion blickt, betritt unweigerlich das Reich der Unbestimmtheit. Tatsache ist, das jedwede Funktion, die einen Verweis auf ein lokales Objekt zurückgibt, kaputt ist."Das stimmt doch nicht, wenn ich mir mein Programm oben anschaue, oder?
Kann mir vielleicht jemand erklären was genau bei der Rückgabe eines Wertes intern passiert. Ich hab das immer so verstanden, die Anweisung "return xyz" sorgt dafür das eine temporäre Kopie (vermutlich shallow copy, oder???) von xyz kurzzeitig angelegt wird. Und diese Kopie wird dann der zuzuweisenden Variablen zugewiesen.
Wen dem so ist kann man doch mit gutem Gewissen lokale Integers , Doubles , ..... usw. als return Wert verwenden.Desweiteren wird dann der UseCount des Shared pointers auch nicht auf Null gesetzt wodurch auch der angeforderte Speicherbereich erhalten bleibt.
Kann mir das mal bitte jemand erklären.
Gruss
Daniel""
-
test123321 schrieb:
Das stimmt doch nicht, wenn ich mir mein Programm oben anschaue, oder?
Doch, das stimmt. Das Zauberwort ist "Verweis auf lokales Objekt" - wenn du nur einen Pointer oder eine Referenz auf ein Lokales Objekt zurückgibst kommt murks raus, weil das referenzierte Objekt eben nicht mehr existiert.
Kann mir vielleicht jemand erklären was genau bei der Rückgabe eines Wertes intern passiert. Ich hab das immer so verstanden, die Anweisung "return xyz" sorgt dafür das eine temporäre Kopie (vermutlich shallow copy, oder???) von xyz kurzzeitig angelegt wird. Und diese Kopie wird dann der zuzuweisenden Variablen zugewiesen.
Wen dem so ist kann man doch mit gutem Gewissen lokale Integers , Doubles , ..... usw. als return Wert verwenden.Desweiteren wird dann der UseCount des Shared pointers auch nicht auf Null gesetzt wodurch auch der angeforderte Speicherbereich erhalten bleibt.
Richtig. Anders wäre das mit der Rückgabe aus Funktionen auch garnicht machbar.
-
Dann reicht also:
return values;und
return boost::shared_ptr< std::vector< double > > (values);
wäre doppelt gemoppelt, oder?Wiso favorisiert Scott Meyers dann die Version "return boost::shared_ptr< std::vector< double > > (values);"
-
test123321 schrieb:
Wiso favorisiert Scott Meyers dann die Version "return boost::shared_ptr< std::vector< double > > (values);"
Woraus leitest du das ab?
-
Tschuldigung hab nicht genau hingesehen. In seinem Buch steht sowas :
const Rational& operator* (const Rational & lhs, const Rational &rhs) { Rational result(lhs.n*rhs.n, lhs,d*rhs.d); return result; }
Daneben steht "Warnung schlechter Code!" .
Ich hatte das Referenzzeichen hinter Rational im Funktionsrumpf übersehen.
Vielen Dank für eure Antworten damit is jetzt alles klar.
-
Vielleicht noch zur Ergaenzung.
Die beste Version nach Scott Meyers wäre:
inline const Rational operator* (const Rational&lhs, const Rational& rhs) { return Rational (lhs.n*rhs.n, lhs,d*rhs.d); }
Stichwort : Returnwertoptimierung
-
test123321 schrieb:
Vielleicht noch zur Ergaenzung.
Die beste Version nach Scott Meyers wäre:
inline const Rational operator* (const Rational&lhs, const Rational& rhs) { return Rational (lhs.n*rhs.n, lhs,d*rhs.d); }
Stichwort : Returnwertoptimierung
Scott Meyers geht auf RVO gar nicht ein, sein Argument ist nur as-if-Optimierung, die ein relativ schwaches Argument darstellt (und bei selbst-definierten Copy-ctors im Allgemeinen gar nicht möglich wäre).
Nicht zu vergessen wäre in dem Zusammenhang ohnehin noch NRVO - es spielt deshalb hier keine Rolle, ob nun erst eine benannte Variable initialisert wrd, oder ein unbenanntes temporäres Objekt zur Initialisierung des Rückgabeobjektes benutzt wird. Je komplexer die Angelegenheit wird, um so mehr ist die Benutzung eines benannten Objektes angebracht, um die Übersicht zu wahren.
-
camper schrieb:
sein Argument ist nur as-if-Optimierung, die ein relativ schwaches Argument darstellt (und bei selbst-definierten Copy-ctors im Allgemeinen gar nicht möglich wäre).
So lange ein selbst definierter Copy-Ctor keine Systemaufrufe, oder Dinge in einer anderen Library/DLL verwendet, sehe ich keinen Grund, warum hier "as-if" Optimierung im Allgemeinen nicht möglich sein sollte.
Mit Link-Time-Code-Generation geht da ziemlich viel.
-
hustbaer schrieb:
camper schrieb:
sein Argument ist nur as-if-Optimierung, die ein relativ schwaches Argument darstellt (und bei selbst-definierten Copy-ctors im Allgemeinen gar nicht möglich wäre).
So lange ein selbst definierter Copy-Ctor keine Systemaufrufe, oder Dinge in einer anderen Library/DLL verwendet, sehe ich keinen Grund, warum hier "as-if" Optimierung im Allgemeinen nicht möglich sein sollte.
Mit Link-Time-Code-Generation geht da ziemlich viel.Das mag alles sein, deshalb auch "im Allgemeinen". Der Punkt ist hier, dass wenn wir annehmen, dass der Compiler diese ganzen -O9 Optimierungen durchführen kann, das auch bei anderer Formulierung des Codes der Fall sein dürfte, was die Diskussion wieder zum Ausgangspunkt zurückführt.
Im Gegensatz dazu ist das Potential für (N)RVO unmittelbar an der entsprechenden Codestelle zu erkennen. Denn ob diese Optimierung (eigentlich ja keine echte Optimierung, weil ein anderes Programm erzeugt wird) möglich ist, hängt eben nicht von anderen Teilen des Programmes ab, somit ist es einfach, hiervon zuverlässig Gebrauch zu machen.