Das ist alles so schön bunt hier, oder eben nicht...
-
Ich habe hier noch eine Anfängerfrage:
Ich habe an verschiedenen Stellen gesehen, dass Pointer auf Arrays, bzw. die Arrays mit "new" angelegt werden. Allerdings gibt es eben auch viele Stellen ohne "new". Daher stellt sich mir die Frage, ob new einen Vorteil hat oder nur mehr schmückendes Beiwerk. Java benutzt glaube ich new, bei c++ war ich bisher der Ansicht, es ist nicht notwendig.
Was sagen denn die geneigten Coder dazu?
P.S. Obwohl ich derzeit nicht vor habe öfters zu posten, wäre ein Zeilenumbruch ganz schön. Dürfte durch das entsprechende html Steuerzeichen gehen. Was meint Ihr?
-
new reserviert einfach nur Speicher, das sollte die Frage eigentlich schon beantworten.
Zeilenumbruch: "\n"
-
"new" reserviert Speicher auf dem Heap, andernfalls liegt der Speicher immer auf dem Stack. Der Heap bezeichnet dabei den gesamten Arbeitsspeicher, den es in deinem System gibt - der mit new reservierte Speicher kann entsprechend überall im Arbeitsspeicher liegen. Beim Stack ist das anders. Der Stack liegt zwar natürlich auch im Arbeitsspeicher, neue Daten werden aber immer ans Ende des Stacks angefügt - es handelt sich hier also um eine Datenstruktur die immer zusammenhängend im Speicher liegt.
Weiteres: Funktionsaufrufe legen eine Rücksprungadresse + Argumente auf den Stack. Ein Zeiger auf das Ende des Stacks ist quasi überall in deinem Programm vorhanden. Die Funktion kann über diesen Zeiger auf ihre Argumente zugreifen und weil sie weiß, wieviele Argumente sie hat und auch deren Größe kennt, weiß sie auch wo die Rücksprungadresse zu finden ist. Diese Adresse bezeichnet den Ort, von dem aus die Funktion aufgerufen wurde und an dem es jetzt nach Beendigung der Funktion weitergehen soll. (näheres findest du via Google: Aufrufkonvention / engl. calling conventions)
Wenn du innerhalb der Funktion Variablen deklarierst, landen die auch auf eben diesem Stack, außer du verwendest "new".
Die Vor-/Nachteile sind folgende:
Variablen auf dem Stack werden automatisch aufgeräumt, sobald sie aus dem Scope fallen. Am Beispiel der Funktion wäre das z.B. der Rücksprung zum Aufrufer. Dazu ist als Hintergrundwissen auch nochmal gut zu wissen, wie ein Stack funktioniert (man legt was drauf oder nimmt was runter). In C++ ist ein Scope alles innerhalb von geschweiften Klammern. Alles was nach einer öffnenden geschweiften Klammer kommt, liegt in einem eigenen Scope und wird wieder vernichtet (d.h. vom Stack geräumt) sobald die schließende Klammer folgt.Variablen, die per "new" definiert wurden, befinden sich an einem beliebigen Ort und unterliegen somit auch nicht der Kontrolle des Stacks. Ein Aufruf von "new" liefert immer einen Zeiger zurück. Der Speicher bleibt solange belegt, bis du ihn mit einem "delete"-Aufruf wieder freigibst. Zum Programmende wird sämtlicher Speicher auf dem Heap automatisch freigegeben, das macht dann aber das Betriebssystem - eigentlich wäre es dein Job. Wenn du einen Zeiger verlierst, den dir "new" gegeben hat und du kein delete Aufgerufen hast, entsteht ein so genanntes Speicherloch. Dieser Speicherbereich ist aus Sicht des Betriebssystems belegt - du selbst kannst aber nicht mehr darauf zugreifen. Wenn du das zu oft machst, kann dir schnell der Speicher ausgehen. Zu einem Problem wird es vorallem, wenn dein Programm lange läuft, andernfalls wird der Speicher zu Programmende wie gesagt wieder frei.
"new" brauchst du vorallem, wenn du viel Speicher willst. Die Größe des Stacks ist nämlich immer limitiert, weil er zusammenhängend im Speicher liegen soll und deshalb zum Programmstart in einem Stück alloziert werden muss. Übliche Größen sind 1-4MB. Im Handbuch deines Compilers kannst du nachlesen, wie groß dein Stack per default ist - du kannst die Größe innerhalb von bestimmten Grenzen auch anpassen. Speicher auf dem Heap verwendest du beispielsweise auch, wenn du ein Array aus einer Funktion zurückliefern willst. Wenn du in der Funktion "int array[5]" schreibst, würde es ja am Ende des Stacks erzeugt und zum Funktionsende gelöscht werden - der zurückgelieferte Zeiger wäre also "wild", zeigt auf einen gelöschten Speicherbereich. Also holst du dir stattdessen Speicher vom Heap - den muss der Aufrufer dann aber selbst löschen. In dem Fall ist es wichtig, dass du klare Konventionen hast, wer Speicher zu löschen hat.
In den meisten Fällen verwendest du in C++ Objekte um Speicher auf dem Heap zu verwalten. Einfaches Beispiel: Ein int-Array als C++ Objekt kann kopiert werden, gelöscht werden. Bei diesen beiden Aktionen wird jeweils eine Methode aufgerufen (Kopierkonstruktor bzw. Destruktor). In diesen "Methoden" kannst du dann die Funktionalität des Speichermanagements implementieren. std::vector macht das auch irgendwie so.
So! Vermutlich deutlich mehr Information, als du haben wolltest, aber wenn du bis hierhin gelesen hast ist das auf jeden Fall gut. Ich finds schön vorallem auch als Anfänger mal nen etwas weitscheifenderen Überblick zu bekommen. Wenn du in deinem C++ Buch oder womit auch immer du lernst, Fortschritte machst, hast du davon schonmal gehört und es lernt sich gleich viel leichter.
Gute Nacht.
-
dies Text ist so schön wie die Erklärung von ein Buch. Was gelernt. Danke
-
Nur weil etwas nicht mit "new" angefordert wurde, heißt es noch lange nicht das es automatisch auf dem Stack liegt. Denn sonst würden ja alle Membervariablen einer Klasse die mit new angefordert wurde ebenfalls auf dem Stack liegen, was sie nicht tun.

-
Schalten Sie auch morgen wieder ein, wenn es heisst:
Neues vom objektorientierten Programmieren
Erklärung ist grob angekommen, vielen Dank.
-
Fellhuhn schrieb:
Nur weil etwas nicht mit "new" angefordert wurde, heißt es noch lange nicht das es automatisch auf dem Stack liegt. Denn sonst würden ja alle Membervariablen einer Klasse die mit new angefordert wurde ebenfalls auf dem Stack liegen, was sie nicht tun.

Wenn sie mit new angefordert wurden, wurden sie nicht nicht mit new angefordert, richtig? Mit Objekten kann natürlich auch Speicher auf dem Heap belegt werden, aber die Objekte selber liegen immer auf dem Stack.