Wie funktioniert die Speicherverwaltung hinter std::strings ?



  • Hallo C++ Board,
    ich würde mich zwar keinen richtigen Anfänger mehr nennen, habe aber trotzdem eine Grundlegende Frage, die mir immer noch nicht richtig klar wurde:

    std::string str;
    char* cstr1 = new char[10]; 
    char* cstr2 = "hallo";
    
    // Frage 1:
    delete [] cstr1; 
    delete [] cstr2; // Ist der zweite String auch dynamisch ?
    
    // Frage 2:
    str = cstr1; 
    delete [] cstr1; /* Benutzt str den Speicher von cstr1 weiter und wird er dann auch wieder von str freigegeben ? */
    
    //Frage 3:
    str = "hallo";
    cstr1 = str.c_str();// Bekomme ich hier nur den Pointer auf einen c string innerhalb von str ? 
    delete [] cstr1; //  oder kann/muss ich den Speicher wieder selber freigeben ?
    

    Ich hoffe ihr versteht was ich meine.
    Danke im voraus.



  • std::string str;
    char* cstr1 = new char[10]; 
    char* cstr2 = "hallo"; // <- korrekt wäre const char* cstr2
    
    // Frage 1:
    delete [] cstr1; 
    delete [] cstr2; // <- SCHLECHT, da cstr2 nicht mit new[] angefordert wurde.
                     //    Stringliterale wie "hallo" räumen sich selbst auf.
    
    // Frage 2:
    str = cstr1; 
    delete [] cstr1; // <- SCHLECHT, da str die Zeichen kopiert und selbst verwaltet.
                     //    Du hast also zwei delete[] auf den selben Speicherbereich, nicht gut.
    
    //Frage 3:
    str = "hallo";
    cstr1 = str.c_str(); // <- geht nicht, da c_str() einen Zeiger auf const char zurückgibt.
                         //    Aber ja, c_str() gäbe Lesezugriff auf einen C-String.
    delete [] cstr1; // <- SCHLECHT, der Speicher gehört nicht dir.
    


  • Nexus schrieb:

    delete [] cstr1; // <- SCHLECHT, da str die Zeichen kopiert und selbst verwaltet.
                     //    Du hast also zwei delete[] auf den selben Speicherbereich, nicht gut.
    

    Wenn der string aber den speicher kopiert, dann muss man es doch von hand löschen...



  • Nein. Das übernimmt eben std::string für dich.



  • drakon schrieb:

    Nein. Das übernimmt eben std::string für dich.

    In dem Fall aber doch nicht, weil sich str eine Kopie zieht, und nicht den cstr1-Zeiger als neuer Member nimmt.
    http://www.cplusplus.com/reference/string/string/operator=/
    cstr1 wird mit new[] erstellt, deshalb braucht es auch ein delete.
    (der Quote war ja auf das "str = cstr1", und nicht "cstr1 = str.c_str()").

    Mist, auf den Zweiten Blick sehe ich aber trotzdem ein Problem.

    char* cstr1 = new char[10];
    
    // Frage 1:
    delete [] cstr1;
    
    // Frage 2:
    str = cstr1;
    delete [] cstr1;
    

    Es ist ohne neue Erstellung ein zweiter delete auf einen bereits gelöschten Speicherbereich. Das geht definitiv schief.

    BTW:

    char* char_array = std_string.c_str();
    

    wird eh nicht kompilieren, da eine Zuweisung des c_str() (=const char*) an char_array (=char*) nicht funktioniert. Dafür ist dann für den allernötigsten Ausnahmefall const_cast zu verwenden.



  • Anworten im Code

    std::string str;
    char* cstr1 = new char[10]; 
    char* cstr2 = "hallo";
    
    // Frage 1:
    delete [] cstr1; // ok, speicher ist freigegeben
    delete [] cstr2; // Ist der zweite String auch dynamisch ?
    // cstr2 zu löschen ergibt "undefined behavior", d.h. man darf das nicht machen
    
    // Frage 2:
    str = cstr1; // undefined behavior, da cstr1 schon freigegeben ist
    delete [] cstr1; /* Benutzt str den Speicher von cstr1 weiter und wird er dann auch wieder von str freigegeben ? */
    // wieder undefined behavior
    
    // Nachdem Speicher mit delete oder delete[] freigegeben worden ist, dürfen die Zeiger nicht mehr dereferenziert werden!
    
    //Frage 3:
    str = "hallo";
    cstr1 = str.c_str();// Bekomme ich hier nur den Pointer auf einen c string innerhalb von str ?
    // ja,
    delete [] cstr1; //  oder kann/muss ich den Speicher wieder selber freigeben ? 
    // nein! der std::string verwaltet das für Dich. Es wird keinerlei Kopie angelegt, die vom außerhalb verwaltet werden müßte.
    


  • drakon schrieb:

    Nein. Das übernimmt eben std::string für dich.

    cstr1 wurde mit new[] erzeugt und muss mit delete [] gelöscht werden auch wenn sich ein std::string eine Kopie davon genommen hat. string verwaltet, wie du ja schon gesagt hast eine Kopie.



  • brotbernd schrieb:

    drakon schrieb:

    Nein. Das übernimmt eben std::string für dich.

    cstr1 wurde mit new[] erzeugt und muss mit delete [] gelöscht werden auch wenn sich ein std::string eine Kopie davon genommen hat. string verwaltet, wie du ja schon gesagt hast eine Kopie.

    Ich habe das auch auf die Kopie bezogen.
    Die Kopie muss nicht mehr selbt verwaltet werden. Den ursprünglichen selbstverständlich doch (was er ja auch macht, auch wenn es fehlerhaft ist).



  • drakon schrieb:

    Ich habe das auch auf die Kopie bezogen.
    Die Kopie muss nicht mehr selbt verwaltet werden. Den ursprünglichen selbstverständlich doch (was er ja auch macht, auch wenn es fehlerhaft ist).

    Schon klar, dass du das so meintest. Mir schien blos als wäre die Frage anders gestellt gewesen und der Threadersteller durch die Antwort evtl. noch verwirrter 😉

    3 Fragen als zusammenhängenden Code darzustellen ist übrigens ziemlich verwirrend. Das hätte man besser trennen sollen. 3 mal cstr1 zu löschen sieht etwas seltsam aus, auch wenn man sich denken kann, dass es nicht als zusammenhängender Code gemeint war.



  • Ja ist wahrscheinlich schon nicht so übersichtlich geworden.

    Mal sehen, ob shorty0802 noch fragen hat.


Anmelden zum Antworten