Hallo zusammen, wenn ich in Arduino einen String aus einer Funktionn zurückgebe, wann wird dieser entfernt? Muss ich selbst delete aufrufen? Beispiel 1: Ist das so machbar und korrekt? String GPS::get_gps_buffer(){ char gps_buffer[] = "testmich"; return String(gps_buffer); } Wann wird der String wieder entfernt? Eigentlich doch beim verlassen der Funktion, aber es funktioniert zur Laufzeit. Oder habe ich ein Memory-Leak produziert? Danke für fundierte Erklärungen. Viele Grüße Stefan
Ich kenne jetzt Arduino nicht, aber etwas C++. Du hast prinzipiell Recht damit, daß gps_buffer[] nur innerhalb der Funktion lebt, und ein Pointer darauf nach dem Aussprung nicht mehr dereferenziert werden darf. Wenn die Funktion einen char* zurückgeben würde, gäbe das einen üblen Crash. Deine Funktion gibt aber per Definition keinen char[], sondern einen String zurück. Was immer auch ein String "in Arduino" genau ist, weiß ich zwar nicht, aber sehr vermutlich ist das nichts anderes als std::string. Da findet ein cast statt, bei dem der Inhalt von Buffer in den String kopiert wird, und damit der Aussenwelt der Funktion erhalten bleibt. Oliver
Hallo Oliver, ein Cast kann das nicht sein, sondern der Konstruktur wird aufgerufen. Das Objekt der Klasse String sollte so aber trotzdem auf dem Stack liegen, denn ich habe ja kein "new" gemacht. Etwas ausführlicher: String GPS::get_gps_buffer(){ char gps_buffer[] = "testmich"; String tmp = String(gps_buffer); // tmp liegt auf dem Stack, oder? return tmp; // refernz auf tmp geht nach aussen, aber tmp stirbt? } Ich hoffe meine Frage ist nun klarer. Was passiert mit "tmp" beim return aus "get_gps_buffer"? Und wenn tmp ausserhalb weiterlebt, wie werde ich das Objekt wieder los? VG Stefan
Stefan Schuster schrieb: > Ich hoffe meine Frage ist nun klarer. Was passiert mit "tmp" beim return > aus "get_gps_buffer"? Und wenn tmp ausserhalb weiterlebt, wie werde ich > das Objekt wieder los? das passiert selber String s s = GPS::get_gps_buffer(); get_pgs_buffer liefert das string objekt zurück. Dann wird der Zuweisungsoperator von s ausgerufen. Nach dem denn s den inhalt hat, wird das objekt zerstört. Und jetzt sollte auch klar sein, warum das keine gute Idee ist das ganze ist viel zu langsam.
Stefan Schuster schrieb: > Ich hoffe meine Frage ist nun klarer. Was passiert mit "tmp" beim return > aus "get_gps_buffer"? Es wird konzeptionell eine Kopie davon erzeugt, die in einem temporären Objekt weiterlebt und mit der der Aufrufer etwas macht ... zb ein einer Objektvariablen speichern. Danach wird das temporäre Objekt zerstört. temp selbst ist schon mit dem Ende der Funktion zerstört worden. (*) > Und wenn tmp ausserhalb weiterlebt, wie werde ich > das Objekt wieder los? geschieht alles von alleine. (*) hört sich jetzt schlimmer an als es ist. Das meiste davon wird vom Compiler wegoptimiert.
Danke! jetzt hab ichs verstanden. Und ja, jetzt ist auch klar dass das keine gute Idee ist ;-) Viele Grüße Stefan
Stefan Schuster schrieb: > Danke! > > jetzt hab ichs verstanden. Und ja, jetzt ist auch klar dass das keine > gute Idee ist ;-) Was ist keine gute Idee? Ein Objekt aus einer Funktion herausgeben? Nun, ich kenne die String Klasse vom Arduino nicht. Aber wenn die halbwegs was taugt, dann ist es sogar eine extrem gute Idee, ein String Objekt aus einer Funktion herauszugeben.
Peter II schrieb: > Und jetzt sollte auch klar sein, warum das keine gute Idee ist das > ganze ist viel zu langsam. Immer langsam mit den jungen Pferden. Die Compiler beherrschen das schon, wie man sowas schnell macht. In C++ darf man nicht immer nach dem gehen, was die Sprache konzeptionell vorschreibt. Das im Standard benutzte Objektmodell ist oft sehr langatmig und sieht auf den erste Blick umständlich aus. Die Compiler haben aber auch eine Entwiklungszeit hinter sich, die die Dinge wieder schnell machen, indem vieles wieder wegoptimiert wird.
Karl Heinz Buchegger schrieb: > Immer langsam mit den jungen Pferden. > Die Compiler beherrschen das schon, wie man sowas schnell macht. das sag doch mal bitte wie er das macht? Meines wissen ist es mit neue C++ standard definiert das er keine Kopie von string machen braucht. Oder hoft du darauf der String selber eine referenzcounting macht?
Peter II schrieb: > Karl Heinz Buchegger schrieb: >> Immer langsam mit den jungen Pferden. >> Die Compiler beherrschen das schon, wie man sowas schnell macht. > > das sag doch mal bitte wie er das macht? Dein Google Stichwort lautet Named Return Value Optimization
Karl Heinz Buchegger schrieb: > Peter II schrieb: >> Karl Heinz Buchegger schrieb: >>> Immer langsam mit den jungen Pferden. >>> Die Compiler beherrschen das schon, wie man sowas schnell macht. >> das sag doch mal bitte wie er das macht? > Dein Google Stichwort lautet > Named Return Value Optimization und das geht nur wenn man auch screibt: String s = GPS::get_gps_buffer(); wenn s schon vorher definiert ist und man nur noch s = GPS::get_gps_buffer(); schreibt, dann geht es schon nicht mehr.
Nachtrag: ob es bei bei String s s = GPS::get_gps_buffer(); nciht geht, dann ich nicht genau sagen, aber hier geht es auf jeden fall nicht mehr String s("xyz"); s = GPS::get_gps_buffer();
Peter II schrieb: > Karl Heinz Buchegger schrieb: >> Peter II schrieb: >>> Karl Heinz Buchegger schrieb: >>>> Immer langsam mit den jungen Pferden. >>>> Die Compiler beherrschen das schon, wie man sowas schnell macht. >>> das sag doch mal bitte wie er das macht? >> Dein Google Stichwort lautet >> Named Return Value Optimization > > und das geht nur wenn man auch screibt: > > String s = GPS::get_gps_buffer(); > > wenn s schon vorher definiert ist und man nur noch > > s = GPS::get_gps_buffer(); > > schreibt, dann geht es schon nicht mehr. Dann erzeug halt ein neues Objekt! In C++ sollte man nicht ohne Grund von der Technik des 'alle Variablen an den Anfang eines Blocks' Abstand nehmen. "Resource Allocation is initialization" (oder kurz RAII) ist das Gebot der Stunde. D.h. du willst soeviel wie nur irgendwie geht in Form von Initialisierungen durchführen anstatt Variablen ständig rumlungern zu haben. In C++ ist es völlig normal for( i = 0; i < 10; ++i ) { String s( i ); mach was mit s } zu haben, und so scheinbar innerhalb der SChleife laufend Objekte zu erzeugen und zu zerstören. Die Compiler sind darauf ausgelegt, damit klarzukommen und das effektiv zu handhaben.
Karl Heinz Buchegger schrieb: > Dann erzeug halt ein neues Objekt! > In C++ sollte man nicht ohne Grund von der Technik des 'alle Variablen > an den Anfang eines Blocks' Abstand nehmen. mir ist das klar, aber das muss man ebend wissen und man kann nicht pauschal sagen ein String zurückzugeben ist sinnvoll.
Peter II schrieb: > Karl Heinz Buchegger schrieb: >> Dann erzeug halt ein neues Objekt! >> In C++ sollte man nicht ohne Grund von der Technik des 'alle Variablen >> an den Anfang eines Blocks' Abstand nehmen. > > mir ist das klar, aber das muss man ebend wissen und man kann nicht > pauschal sagen ein String zurückzugeben ist sinnvoll. verglichen mit der Alternative und dem Gewirx, das man konkret bei Strings mit char-Arrays hat, ist fast alles besser :-)
Karl Heinz Buchegger schrieb: > verglichen mit der Alternative und dem Gewirx, das man konkret bei > Strings mit char-Arrays hat, ist fast alles besser :-) Natürlich nur, wenn die Arduino String Klasse ihrem Namen auch ein bischen Ehre macht. Ich kenn die nicht, daher mit Vorsicht zu geniessen.
Karl Heinz Buchegger schrieb: > verglichen mit der Alternative und dem Gewirx, das man konkret bei > Strings mit char-Arrays hat, ist fast alles besser :-) oder einfach andere alternative suchen GPS::get_gps_buffer( String& s ){ s = String(gps_buffer); }
Auch C++ kann nicht magisch Speicher hervorzaubern. Der Stackpointer muß nach dem Verlassen einer Funktion auf genau der gleichen Adresse stehen, wie beim Eintritt. Aller durch die Funktion benutzter Speicher kann zwar noch die Daten beinhalten, wird aber bei nächster Gelegenheit überschrieben. Der Compiler kann höchstens malloc() aufrufen und dort Speicher anfordern. Dieser muß dann aber auch irgendwann wieder freigegeben werden, sonst ist nach z.B. 1000 Funktionsaufrufen aller RAM belegt. Es muß also eine Instanz geben, die spätestens vor dem nächsten Aufruf ein free() auf den vorherigen Speicher macht. Der Compiler müßte also den letzten Lesezugriff vor dem nächsten Aufruf suchen und dort ein free() anhängen. Schwierig bis unmöglich wirds aber, wenn der Aufruf und das Lesen von Bedingungen abhängt. Sowas traue ich dem Compiler auch nicht zu. Der AVR-GCC meckert ja schon rum, wenn er meint, eine Variable in einer Schleife wäre nicht initialisiert, ich aber anhand des Ablaufs ganz genau sehen kann, daß sie vor dem ersten Lesen initialisiert wird. In C ist die übliche Methode, der Aufrufer kümmert sich um den Speicher und übergibt eine Pointer darauf. Und wenn man es richtig gut machen will, übergibt man noch die Länge dieses Speichers, damit der Aufgerufene weiß, wieviel er hinein schreiben darf.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.