Forum: Compiler & IDEs Arduino: String Objekt aus Funktion zurückgeben


von Stefan S. (Firma: keine) (stefan_s) Benutzerseite


Lesenswert?

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

von Oliver (Gast)


Lesenswert?

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

von Stefan S. (Firma: keine) (stefan_s) Benutzerseite


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Stefan S. (Firma: keine) (stefan_s) Benutzerseite


Lesenswert?

Danke!

jetzt hab ichs verstanden. Und ja, jetzt ist auch klar dass das keine 
gute Idee ist ;-)

Viele Grüße
Stefan

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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();

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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 :-)

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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);
}

von Peter D. (peda)


Lesenswert?

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
Noch kein Account? Hier anmelden.