Forum: PC-Programmierung Pointer und new


von Pointer (Gast)


Lesenswert?

Hallo,
ich beschäftige mich ein wenig mit C++ und bin auf die Funktion new 
gestoßen. Ich frage mich wozu das sinnvoll sein soll.

Wenn ich z.B. einen Pointer deklariere:
1
int *pointer;

Dann zeigt er schon auf eine Speicheradresse, ohne das ich ihm eine 
übergebe.
Habe das geprüft mit:
1
cout<< &pointer;
Das lässt doch darauf schließen das er schon Speicher reserviert oder 
nicht? Das selbe passiert doch hier auch:
1
int *pointer = new int;

Hat jemand vielleicht ein Besipiel wo das new tatsächlich einen Nutzen 
hat?

Grüße

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

Pointer schrieb:
> cout<< &pointer;

das ist nicht die Adresse auf die der Pointer zeigt, sondern die 
Adresse, wo der Pointer liegt.

von Sven B. (scummos)


Lesenswert?

foo* x ist ein unintialisierter Pointer. Wenn du mit dem irgendwas 
machst außer rumkopieren (zum Beispiel *x = a oder was auch immer) ist 
das undefiniertes Verhalten und lässt im Zweifel dein Programm 
abstürzen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Pointer schrieb:
> Das lässt doch darauf schließen das er schon Speicher reserviert oder
> nicht?

Nein. Das lässt nicht darauf schließen.

Ein Pointer zeigt immer irgendwohin. Das liegt in der Natur der Sache; 
ein Pointer ist nur eine Adresse.

Aber das, worauf er zeigt, ist, solange er nicht initialisiert wird, 
halt irgendwas. Was da halt zufällig im Speicher 'rumdümpelt (sofern 
an der betreffenden Adresse überhaupt Speicher ist).

von Pointer (Gast)


Lesenswert?

Ja ok, bisschen blöd ausgedrückt.
Das heißt doch aber, dass für diesen Pointer Speicher reserviert wurde 
oder nicht?

von Peter II (Gast)


Lesenswert?

Pointer schrieb:
> Ja ok, bisschen blöd ausgedrückt.
> Das heißt doch aber, dass für diesen Pointer Speicher reserviert wurde
> oder nicht?

ja, aber nur für den Pointer und nicht auf das wo er hinzeigt.

von Sven B. (scummos)


Lesenswert?

Für den Pointer selber ja, also 4 oder 8 Bytes. Aber nicht für das 
Objekt, auf das der Pointer zeigt. Der Pointer selber liegt ja einfach 
auf dem Stack.

: Bearbeitet durch User
von Pointer (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Aber das, worauf er zeigt, ist, solange er nicht initialisiert wird,
> halt irgendwas. Was da halt zufällig im Speicher 'rumdümpelt (sofern
> an der betreffenden Adresse überhaupt Speicher ist).

Achso, also sage ich mit dem new, dass dieser Adressbereich tatsächlich 
für den zukünftigen Inhalt von dem Pointer reserviert wird?

Aber moment? Dann wäre es doch eine Variable.
Irgendwie verstehe ich gerade garnichts mehr.

von Sven B. (scummos)


Lesenswert?

Man kann's eigentlich nicht verstehen wenn man in zu abstrakten 
Begriffen denkt. Geh mal einen Schritt zurück.

Erstmal gibt es den Heap und den Stack. Speicher auf dem Stack wird 
immer implizit reserviert, indem man einfach sowas hinschreibt wie
Foo x;
Dann kriegst du sizeof(Foo) Bytes an Stack-Speicher für ein Objekt des 
Typs Foo. &x ist die Adresse von dem Stack-Speicher. Wenn du schreibst
Foo* x;
dann kriegst du sizeof(Foo*) (das ist eigentlich immer 4 oder 8) Bytes 
an Stack-Speicher für ein Objekt des Typs Foo* (das ist eigentlich immer 
eine Zahl mit 4 oder 8 Bytes). Das ist aber nur der Pointer, den 
eigentlichen Inhalt des Objekts kannst du bisher noch nirgends ablegen.

Speicher auf dem Heap wird explizit reserviert, indem man das 
Betriebssystem danach fragt. Das tun Funktionen wie malloc oder new. 
Wenn du schreibst
new Foo;
dann kriegst du eine Adresse zurück, an der das Betriebssystem 
sizeof(Foo) Bytes an Speicher für dich reserviert hat. Außerdem wird der 
Konstruktur von Foo aufgerufen, wobei this auf den neu reservierten 
Speicher zeigt.

Wenn du
Foo* x = new Foo
schreibst, passiert beides. Es werden sizeof(Foo*) Bytes auf dem Stack 
reserviert, und sizeof(Foo) Bytes auf dem Heap, und der erste 
Speicherbereich wird mit der Adresse des zweiten befüllt.

In modernem C++ versucht man explizite Verwendung von new meist zu 
vermeiden, weil aller Speicher der mit new reserviert wird auch mit 
delete wieder freigegeben werden muss (Speicher auf dem Stack hingegen 
wird automatisch implizit wieder freigegeben, sobald der Kontrollfluss 
die nächste schließende } erreicht). Vergisst man dass, hat man ein sog. 
Memory Leak. Dazu gibt es so Konzepte wie std::shared_ptr.

: Bearbeitet durch User
von Pointer (Gast)


Lesenswert?

OK!

Ich glaube ich habe es verstanden.

Also:

Alle Variablen die in Funktionen deklariert werden landen auf dem Stack.
Das bedeutet auch, das nach dem durchlaufen der Funktion der Speicher 
wieder freigegeben wird und die Variable ist nicht mehr existent.

Globale Variablen hingegen landen auf dem Heap. Wenn ich jetzt z.B. eine 
Variable erzeugen möchte, ohne das ich eine Globale Variable Deklariere 
kann ich das also mit dem "new" innerhalb einer Funktion machen. So kann 
ich dann auf dem Heap Speicher reservieren und dann einfach mit einem 
Zeiger darauf zugreifen. Dieser Speicher bleibt dann auch nach dem 
Verlassen der Funktion weiterhin reserviert.
Und stimmt, dafür ist das delete gut. Weil wenn ich ja den Zeiger lösche 
bleibt der Platz weiterhin reserviert und dadurch entsteht dann wohl 
dieser Memory Leak.

Ja?

von Dirk B. (dirkb2)


Lesenswert?

Ein Pointer ist eine Variable, in der eine Adresse gespeichert ist.

Mit
int *pointer;
bekommst du einen Zettel, auf dem du schreiben kannst, wo dein Objekt 
liegt.

Einen Platz für dein Objekt kannst du dir z.B. mit
pointer = new int;
besorgen.

Das &pointer sagt dir nur, wo dein Zettel liegt (nicht was drauf steht).

von Pointer (Gast)


Lesenswert?

Danke auch für die vielen Antworten. Ich habe mich ein wenig unglücklich 
ausgedrückt. Mir ging es auch viel mehr darum "WARUM" man das mit dem 
new überhaupt macht, wenn ich nicht gleich einfach eine Globale Variable 
machen kann. Hätte doch den selben Effekt. Aber ich glaube ich habe es 
mir oben selbst erklärt.

von Pointer (Gast)


Lesenswert?

Pointer schrieb:
> Aber ich glaube ich habe es
> mir oben selbst erklärt.

Aber ich glaube ich habe es mir mit euren guten Antworten erklären 
können. <- So klingt das besser :-)

von Jojo S. (Gast)


Lesenswert?

new nimmt man eben für alles dynamische wo man vorher noch nicht weiss 
wie gross es wird. ZB eine Datei in den Speicher holen: erst die Grösse 
lesen, dann mit new ein Array passender Grösse reservieren.

von (prx) A. K. (prx)


Lesenswert?

Pointer schrieb:
> Globale Variablen hingegen landen auf dem Heap.

Der Heap ist nur für dynamisch erzeugte Daten da. Statische Daten, also 
solche, die Compiler/Linker bereits bekannt sind, sind weder Teil des 
Stacks noch Teil des Heaps. Egal ob die im gesamten Programm bekannt 
sind (global), nur im File (static ausserhalb Funktion) oder nur in der 
Funktion (static innerhalb Funktion).

In
  char *p = malloc(1000);
oder
  X *p = new X;
geht es um zwei völlig getrennte Daten. Die per malloc/new auf dem 
Heap erzeugten Daten, und den wenig Bytes grossen Pointer, der auf sie 
zeigt.

Der Vollständigkeit halber: Lokale Daten (ohne static) darf man sich 
zwar konzeptionell so vorstellen, dass sie stets auf dem Stack landen. 
Aber man sollte sich nicht wundern, wenn sie in der Realität dort nicht 
immer auftauchen. Weil oft in Registern verschwindend, sobald optimiert 
übersetzt wird.

: Bearbeitet durch User
von Mikro 7. (mikro77)


Lesenswert?

Pointer schrieb:
> Alle Variablen die in Funktionen deklariert werden landen auf dem Stack.

Grundsätzlich ja.

Genauer gesagt: Die lokal definierten Variablen werden (normalerweise) 
auf dem Stack platziert (es gibt CPU/Compiler-typische Ausnahmen) oder 
aber auch im Data/Code Segment (Stichwort "static").

> Das bedeutet auch, das nach dem durchlaufen der Funktion der Speicher
> wieder freigegeben wird und die Variable ist nicht mehr existent.

Grundsätzlich ja.

Ausnahme sind "static" Variablen (Data/Code Segment).

Der Begriff "Freigeben" wird bei lokalen Variablen eher nicht benutzt. 
Die Variablen verlassen den "Scope". (einfach mal im Web suchen, bspw. 
http://c.learncodethehardway.org/book/ex22.html).

> Globale Variablen hingegen landen auf dem Heap.

Besser ist die Bezeichnung "dynamische" Variablen.

"Globale" Variablen hingegen liegen im Data oder Code Segment (genauso 
wie local static).

> Wenn ich jetzt z.B. eine
> Variable erzeugen möchte, ohne das ich eine Globale Variable Deklariere
> kann ich das also mit dem "new" innerhalb einer Funktion machen. So kann
> ich dann auf dem Heap Speicher reservieren und dann einfach mit einem
> Zeiger darauf zugreifen. Dieser Speicher bleibt dann auch nach dem
> Verlassen der Funktion weiterhin reserviert.

Ja. Dynamisch allokierte Speicherbereiche sind gültig bis sie 
freigegeben werden (malloc/free). Mit new/delete ist es ähnlich.

> Und stimmt, dafür ist das delete gut. Weil wenn ich ja den Zeiger lösche
> bleibt der Platz weiterhin reserviert und dadurch entsteht dann wohl
> dieser Memory Leak.
>
> Ja?

Genau.

Dynamische Speicherbereiche werden idR benutzt, wenn die Größe zur 
Compilezeit nicht bekannt (bspw. der Inhalt einer zu ladenden Datei) 
oder wenn sehr viel Speicher notwendig ist (da die Stack Größe häufig 
begrenzt ist).

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

Pointer schrieb:
> Danke auch für die vielen Antworten. Ich habe mich ein wenig unglücklich
> ausgedrückt. Mir ging es auch viel mehr darum "WARUM" man das mit dem
> new überhaupt macht, wenn ich nicht gleich einfach eine Globale Variable
> machen kann. Hätte doch den selben Effekt.

Es gibt drei Arten von - nennen wir es Objektlebensdauern, nämlich 
statisch, automatisch und dynamisch.

Alle globalen Variablen sowie die als static deklarierten Member- und 
lokalen Variablen haben statische Lebensdauer. Das heißt, sie existieren 
bis zum Programm-Ende (nach Rückkehr aus main()) und werden dann 
aufgeräumt.

Alle nicht-statischen lokalen Variablen haben automatische Lebensdauer. 
Sie existieren bis zum Ende des Blocks, in dem sie definiert sind.

Alles, was von new oder malloc und Konsorten kommt, ist dynamisch und 
existiert so lange, bis man es explizit delete oder free wieder 
freigibt.

Die dynamischen Objekte haben den Vorteil, daß ich sie nur dann erzeugen 
muss, wenn ich sie auch tatsächlich brauche. Außerdem kann ich dann auch 
z.B. bei einem Array entscheiden, wie groß es sein soll, wenn ich weiß, 
wie viel Platz ich benötige. Bei statischen und automatischen Arrays 
dagegen muß die Größe zur Compilezeit definiert sein. Auch bei der 
objektorientierten Programmierung im Zusammenhang mit Polymorphie wird 
das wichtig, da ich dann auch zur Laufzeit wählen kann, welchen 
dynamischen Typ ein neues Objekt haben soll.

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.