Verständnisfrage zu new



  • [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.html

    Danke 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.


Anmelden zum Antworten