Verständnisfrage zu new
-
Hallo Gemeinde,
ich dachte eigentlich immer das ich das mit new verstanden habe, aber seit geraumer Zeit habe ich einen Wurm im Kopf. Ich habe eine Klasse:
class CTest { // do somthing };Wenn ich für mein zukünftiges Objekt keinen Zeiger benötige, erstelle ich das Objekt so:
CTest test;Wenn ich einen Zeiger für das Objekt benötige oder umgehen will, das es irgendwie kopiert wird, erstelle ich mein Objekt so:
CTest *test = new CTest;Soweit so gut. Jetzt kommt noch ein Faktor hinzu ich erstelle mein Objekt mit new, wenn mein programm "was terminated", sprich wenn es nicht startet. Das Problem habe ich häufiger bei der GUI Programmierung, das ich öfters gezwungen bin mit new zu arbeiten. Das würde mich auch nicht stören wenn ich es verstehen würde warum ich jetzt new nehmen muss. Kann das daran liegen das der Konstruktor voll gestopft ist?
Ich habe die letzten Tage ein paar Bücher gewälzt, in allem sind sie sich einig. Mit new fordert man Speicherplatz auf dem Stack(?) für den Typ an. So weit verstehe ich das. Aber fordert;
CTest test;nicht auch Speicherplatz an? Auf dem Heap? Wann benutze ich new und wann sollte ich es benutzen? Wann ist es sinnvoll und wann nicht? Ich habe das bis jetzt meist so gemacht, wenn mein Objekt oder meine Struktur etwas groß ist einfach new benutzen. Aber ich glaube nicht das meine Vorgehensweise optimal ist. Das ich Speicher mit new anfordern kann ist für mich eine wage Erklärung, da für mich erstmal geklärt werden muss; wozu sollte ich das machen? In meinen Büchern stehen 2 Methoden mit new und ohne (siehe Beispiele oben) es wird auch der rudimentäre Unterschied erklärt, jedoch keine Anwendung. Kann jemand meinen Wurm im Kopf das mal erläutern?
so long
jd
-
Mit new forderst Du Speicher auf dem Heap an.
Auf dem Stack landen Auto-Variablen von Funktionen:void foo() { int a[100]; //landet auf dem Stack }Um zu verhindern, dass eine Klassen-Instanz kopiert werden kann, muss man den Copy-Ctor und den Zuweisungsoperator private machen.
Mit new legt man z.B. Objekt an, die sehr groß werden, oder wenn man zur Compilezeit noch nicht weiss, wie viel Speicher benötigt wird.
-
[cpp]
// testObject wird auf dem Stack gespeichert und automatisch gelöscht,
// sobald testObject seinen Gültigkeitsbereich verlässt
CTest testObject;//testObject wird auf dem Heap erzeugt und muss manuell gelöscht werden
CTest* testObject = new CTest();Vorteil Stack: Keine Speicherlöcher
Vorteil Heap: Nicht alles passt auf den Stack.Am besten nimmste den Stack wann immer möglich. Und den Heap falls möglich in Verbindung mit Smartpointern
-
Also, es gibt Heap und Stack. Auf dem Heap kann man ziemlich viel speichern (bis der RAM voll ist), auf den Stack passt nur begrenzt viel drauf (1-2 MB oder so). Der Stack ist halt eher für temporäre oder kleine Objekte gedacht, da man auf dem Stack richtig schnell Speicher allokieren kann, auf dem Heap dauert's etwas länger.
Kleines Beispiel:void doSomething() { std::ifstream file( "C:/Test.txt" ); std::string line; file >> line; std::cout << line << std::endl; }Die Variablen "file" und "line" werden hier einfach auf dem Stack erstellt, nachdem die Funktion durchgelaufen ist, wird der Stack automatisch wieder zurückgerollt.
Objekte auf dem Heap braucht man nur für ein paar Dinge:
- Optionale Objekte:int* pi = NULL; if ( bedingung ) { pi = new int; *pi = 10; } // Hier _kann_ der Integer hinter pi existieren oder auch nicht. delete pi; // Und wieder wegmachen :)- Variable Größe:
char* file_content = new char [file_size]; // Der Speicherbereich, auf den file_content zeigt, hat die Größe der Datei. delete[] file_content; // Speicher freigeben. Was mit new[] geholt wurde, wird mit delete[] freigegeben.- Objekt soll das Aufrollen des Stacks überleben (fällt mir kein reales Beispiel ein).
- Zur Laufzeit verschiedene Objekte, die sich ähnlich verhalten:
class Animal { public: virtual void beLoud(); // Durch "virtual" wird die richtige Funktion (evtl einer Unterklasse) aufgerufen }; class Dog : public Animal // Ein Hund ist ein Tier { public: void beLoud() { std::cout << "Wuff!" << std::endl; } // Überschreibt die Funktion "beLoud" von Animal }; class Cat: public Animal // Eine Katze ist ein Tier { public: void beLoud() { std::cout << "Miau!" << std::endl; } // Überschreibt die Funktion "beLoud" von Animal }; int main() { std::string animal_name; std::cout << "Geben Sie 'Hund' oder 'Katze' ein: "; std::cin >> animal_name; Animal* a = NULL; if ( animal_name == "Hund" ) a = new Dog(); else if ( animal_name == "Katze" ) a = new Cat(); else { std::cout<<"Falscher Tiername"<<std::endl; return 1; } a->beLoud(); // Gibt "Wuff!" oder "Miau!" aus :) delete a; // Tier löschen.. return 0; }
-
Super vielen Danke Ihr habt mir das einmal aus einem anderen Blickwinkel erklärt. Ob ich das jetzt wirklich verstanden habe wird sich in der Praxis zeigen, aber ich denke mal schon. Alternativ möchte ich noch auf einen Artikel verweisen, wo das Problem auch durch genommen wurde.
http://www.c-plusplus.net/forum/viewtopic-var-t-is-213071-and-postdays-is-0-and-postorder-is-asc-and-start-is-0.htmlDanke für die Hilfe.
so long
jd
-
class FOO{ }; void funktion(){ FOO abc; }abc ist nun ein objekt aufm stack, und seine lebensdauer ist begrenzt im block (hie bps. funktion).
natürlich kannst du auf diese objekt auch über einen zeiger zugriefen, solange das objekt existiert (also in der funktion)
void funktion(){ FOO abc; FOO *p= &abc; // adresse des objekt auf den zeiger des objekttyps zeigen lassen }würdest du den Zeiger aus der funktion bspw. mit retunr übergeben wäre das objekt ja an der stelle des zeiger gelöscht deswegen ungültig.
Würde du das objekt per new in der funktion anlegen, und den zeiger per return übergeben wäre das objekt noch gültig weil es quasi global im arbeitspreicher liegt und nich im stack.
void funktion(){ FOO *p= new FOO(); }
-
BorisDieKlinge schrieb:
Würde du das objekt per new in der funktion anlegen, und den zeiger per return übergeben wäre das objekt noch gültig weil es quasi global im arbeitspreicher liegt und nich im stack.
Nein, es liegt auf dem Heap, und nicht global im Arbeitsspeicher. Zwischen dem globalen Speicherpool und dem Heap besteht nochmal ein ordentlicher Unterschied.
-
ist der heap nicht ein adressbereich der arbeitspeichers?
-
Da hängt (oft) noch das Speichermanagement des OS zwischen. Und dann wird natürlich, im Standardfall, der CRT Heap verwendet.
-
hmm aber trozdem liegen die daten physikalisch auf den RAM Modulen oder net
-
Neee, die landen auf dem USB-Stick.

-
BorisDieKlinge schrieb:
hmm aber trozdem liegen die daten physikalisch auf den RAM Modulen oder net
Die liegen bei den gängigen Betriebssystemen an irgendeiner virtuellen Speicheradresse, die über Pagingmechanismen auf irgendwas physikalisches gemapt wird. Je nachdem, wie die Daten gerade gebraucht werden, kann das auch eine Auslagerungsdatei/Swappartition sein.