PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++ Speicherverwaltung


instinct
2008-12-31, 15:59:05
Mich beschäftigt gerade folgendes Szenario:


list<point> function_xyz()
{
list<point> tmp;

for (int i=0; i < 100; ++i)
{
point p(50, 50);
tmp.push_back(p);
}

return tmp;
}

list ist die List-Implementierung aus der STL. point ist eine einfache Klasse, welche zwei Integer-Werte speichert (es könnte hier auch jedes andere Objekt stehen).

Jetzt bin ich mir bei folgenden Aussagen nicht ganz sicher:
1. Jedes Punkt-Objekt innerhalb der Schleife wird automatisch allokiert, d.h. es wird am Ende des Schleifenblocks automatisch wieder freigegeben. Die Methode push_back() erwartet als Parameter eine Referenz auf ein Objekt.
Komme ich nun also aus dem Schleifenblock raus, sind die Punktobjekt zwar noch im Speicher, wurden aber vom Programm freigegeben und könnten so manipuliert werden?
D.h. es könnte irgendein neues Objekt den Speicher des 1.Punkt-Objektes überschreiben und ich käme in Schwierigkeiten.

2. Bei Rückgabe der Liste, wird die gesamte Liste kopiert und diese Kopie wird zurückgegeben. Also es werden alle Punkt-Objekte kopiert?

3. Wäre es sinnvoller die Punkte dynamisch zu allokieren und später von Hand wieder freizugeben?

...
point *p = new point(50, 50);
...


Ich wäre dankbar, wenn mir da jemand weiterhelfen könnte.

Gnafoo
2008-12-31, 16:17:47
Alles "as far as I know" :D. Ich habe schon eine Weile kein C++ mehr programmiert, also korrigiert mich bitte, wenn ich was Falsches erzähle.

1. Jedes Punkt-Objekt innerhalb der Schleife wird automatisch allokiert, d.h. es wird am Ende des Schleifenblocks automatisch wieder freigegeben. Die Methode push_back() erwartet als Parameter eine Referenz auf ein Objekt.
Komme ich nun also aus dem Schleifenblock raus, sind die Punktobjekt zwar noch im Speicher, wurden aber vom Programm freigegeben und könnten so manipuliert werden?
D.h. es könnte irgendein neues Objekt den Speicher des 1.Punkt-Objektes überschreiben und ich käme in Schwierigkeiten.


Da die Liste direkt Point-Objekte speichert und keine Pointer darauf, wird eine Kopie des Point-Objektes in der Liste abgelegt. Von daher ist es egal, was mit deinem ursprünglichen Objekt passiert. Die Übergabe an push_back per Referenz vermeidet lediglich ein weiteres unnötiges Kopieren.

2. Bei Rückgabe der Liste, wird die gesamte Liste kopiert und diese Kopie wird zurückgegeben. Also es werden alle Punkt-Objekte kopiert?

Ja. Wenn du eine Liste von Pointern verwendest würden nur die Pointer kopiert (dafür musst du die Objekte später irgendwann selbst wieder freigeben). Du kannst die Liste aber auch (afaik, mein C++ ist etwas eingerostet) als Referenz zurückgeben, dann bleibt dir das Kopieren erspart [sorry stimmt nicht, siehe unten]. Natürlich kannst du auch einfach die Liste selbst per new allozieren und einen Pointer zurückgeben. Dann darfst du aber das delete nicht vergessen, daher ist das etwas eklig.

3. Wäre es sinnvoller die Punkte dynamisch zu allokieren und später von Hand wieder freizugeben?

Mein Vorschlag ist immer: mach die einfachere Lösung und wenn das von der Performance nicht reicht, dann kannst du immer noch optimieren. Für eine Liste von Punkten mit ein paar hundert Einträgen braucht dich die Rumkopiererei vermutlich nicht großartig zu kümmern (zumindest bei solchen einfachen Objekten). Vor allem wenn das nicht ständig passiert. Die Rückgabe der Liste könnte man eventuell geschickter gestalten (oder der Funktion eine Liste mitgeben, die von dieser gefüllt wird).

Aber wie gesagt: wenn die Funktion selten aufgerufen wird und nur wenige Einträge im Spiel sind wird das nicht das Riesenproblem sein. Kommt eben etwas auf deinen Anwendungsfall an.

Edit: jedes Objekt einzeln zu allozieren kostet dich ja auch noch einmal Performance (auf dem Stack geht das schneller). Da die Objekte eher klein sind zweifel ich daran, dass dir das wirklich mehr bringt. Ob du jetzt 4 Byte Pointer oder 8 Byte für zwei Integer in der Gegend rumschiebst macht auch kaum einen Unterschied. Außerdem holst du dir das Problem mit dem Freigeben der Objekte ins Haus.

Trap
2008-12-31, 16:39:02
Du kannst die Liste aber auch (afaik, mein C++ ist etwas eingerostet) als Referenz zurückgeben, dann bleibt dir das Kopieren erspart.
Nö, lokale Variablen kann man nicht als Referenz zurückgeben, die werden beim Verlassen der Funktion ungültig.

Das Kopieren der Liste kann man sparen, indem man vom Aufrufer die Liste als Referenz-Parameter mit reingibt.

Gnafoo
2008-12-31, 16:50:40
Hm da hast du wohl recht, danke dir. Macht ja auch keinen Sinn, wenn ich so drüber nachdenke: der Eintrag auf dem Stack wird ja wieder ungültig nach Verlassen der Funktion.

maximAL
2008-12-31, 16:58:15
das kopieren der liste bei der rückgabe werden die meissten compiler eh wegoptimieren, das würde ich nicht anfassen, solang es nicht wirklich nötig ist.

übrigens hat die liste auch einen constructor, mit dem man sie direkt mit n kopien eines objekts initialisieren kann :wink:

instinct
2008-12-31, 17:07:28
Das Beispiel war mehr oder weniger sinnfrei, es ging nur um das Verständnis.
Danke für die Antworten.

Allerdings verstehe ich eine Sache noch nicht so ganz:
Punkt 1:
void push_back ( const T& x );
So ist die push_back Funktion definiert, da wird doch bei der Übergabe das Point-Objektes nicht kopiert? Ich übergebe doch nur die Referenz und diese ist doch am Ende des Schleifenblocks mehr oder weniger illegal?

Coda
2008-12-31, 17:09:58
Es wird innerhalb der Funktion kopiert.