DELETE() - Wird das Objekt wirklich gelöscht?



  • @StudiengangPanik sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    na dass das Objekt und alles was dazu gehört nicht mehr existiert. Wenn durch den DELETE Befehl doch nur der Speicher freigegeben wird aber nicht geleert wird, würde das doch unweigerlich heißen dass je nach Größe meines Speichers bei unendlicher Instanziierung von Objekten ohne das NEW-Statement irgendwann das Programm abschmiert da es keinen freien Speicher mehr gibt da dieser dann ja erst bei Beendigung des Programms freigegeben werden würde.

    Nein, das heisst es nicht. Falls neue Objekte Speicher benutzen, der nicht "geleert" wurde oder wenn das Objekt irgendwann später noch vor dem Moment "geleert" wird, wo der physikalische Speicher ausgeht, stimmt deine Annahme nicht.



  • Vielleicht sollte man bei Speicher nicht von leer / nicht-leer sprechen, sondern von verwaltet und unverwaltet (oder hat jemand noch bessere Ideen?). Mit delete oder free "leerst" du nicht, sondern sagst, dass dieser Speicher jetzt wieder anderweitig verwendet werden kann. Die einfachste Operation für den Speicher ist, einfach nichts zu tun, d.h. wenn ein Wert drin stand, bleibt der unverändert stehen. Nur irgendwo anders wird in irgendwelchen Metadaten gespeichert, dass dieser Speicher nun anderweitig verwendet werden kann. Daher kann es passieren, dass du auch nach dem delete/free immer noch den korrekten Wert liest, aber der Speicher kann inzwischen auch anderweitig verwendet sein.



  • @wob sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    Nur irgendwo anders wird in irgendwelchen Metadaten gespeichert, dass dieser Speicher nun anderweitig verwendet werden kann.

    In welchen Metadateien sollte das sein, dafür gibt es die MMU die das Adressmapping macht. so kann jedes Programm mir jeder beliebigen Adresse im Speicher Starten denn die echte Adresse wo die Daten liegen wird erst bei Zugriff über die MMU ermittelt. Das ist dann auch der gleiche "einfache" Schutz warum man nicht so einfach in den Speicherbereich eines anderen Programmes greifen kann. Aber das führt hier eigentlich zu weit, aber im Grunde sollte man diese zusammenhänge kennen, wenn man Sinnvolöl was Programieren will, sonst geht man eben davon aus das in irgendwelchen Metadateien die Speicherbelegung abgelegt ist.
    Und nein dem TO hier in jedem 2. Post nahe zu legen das er doch std::string benutzen soll, wird für ihn eine weniger Zielführende Hilfe sein. Er soll sich eben mit der Speicherverwaltung auseinander setzen. Aber zum Schluss frag ich mich immer warum Studiert jemand Informatik wenn er sich vorm Studium noch nie mit dem Thema beschäftigt hat und jetzt schon bei nen 3 Zeiler Programm scheitert?

    In diesem Sinne
    Mazze


  • Mod

    @CTecS sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    @wob sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    Nur irgendwo anders wird in irgendwelchen Metadaten gespeichert, dass dieser Speicher nun anderweitig verwendet werden kann.

    In welchen Metadateien sollte das sein, dafür gibt es die MMU die das Adressmapping macht. so kann jedes Programm mir jeder beliebigen Adresse im Speicher Starten denn die echte Adresse wo die Daten liegen wird erst bei Zugriff über die MMU ermittelt

    Jedes malloc allokiert also mindestens eine ganze Speicherseite? Ich denke nicht.



  • @CTecS zitier mal bitte die Zeile in der steht dass ich Informatik studiere. Programmierung als Modul gibt es nicht nur im Informatikstudium, scheinst dich ja gut auszukennen. Abgesehen davon musste ich mich bis jetzt in C# nie so umständlich um die Speicherverwaltung kümmern wie in C oder C++ aber das ist nur meine Meinung und die Kenntnisse in C# sind auch nur auf Ausbildungsbasis da ich nie wirklich Interesse am Coden hatte aber es bleibt nunmal ein Pflichtmodul. ¯_(ツ)_/¯


  • Mod

    @StudiengangPanik sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    Abgesehen davon musste ich mich bis jetzt in C# nie so umständlich um die Speicherverwaltung kümmern wie in C oder C++

    Nee, deine Probleme sind 100% selbstgemacht. Du programmierst C mit new/delete, nicht C++ wie es gedacht ist. Du merkst, dass du korrektes C++ machst, daran dass du dich nicht mehr um Ressourcenverwaltung kümmern brauchst. Das ist natürlich nicht deine Schuld, dass dir das so beigebracht wird, aber es ist auch nicht Problem der Sprache, dass dein Lehrer sie vergewaltigt.



  • @StudiengangPanik sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    Abgesehen davon musste ich mich bis jetzt in C# nie so umständlich um die Speicherverwaltung kümmern wie in C oder C++

    Wahrscheinlich ist "manuelle Speicherverwaltung" und "zeigen, wie komplex C++ sein kann" das Ziel der Übung.

    Ansonsten würde man in C++ deine 28 Zeilen lange Funktion zeichenketteEinlesen() einfach durch ein getline ersetzen. Siehe Beispiel hier: https://en.cppreference.com/w/cpp/string/basic_string/getline

    Oder du würdest den operator>> verwenden, weil du dann beliebige Dinge einlesen könntest und nicht nur Zeichenketten.



  • Puuuuuh.... zeichenketteEinlesen() gewinnt auch mühelos den Worst-Perfomance Award. Du reservierst für jedes Zeichen, das du eingibst, den Speicher neu. Ja, funktioniert, und ja, das passiert wahrscheinlich schneller als jeder Benutzer tippen kann, aber es ist halt schnarchlangsam, weil Speicheranforderungen teuer sind (teuer im Sinne von kostet CPU Zeit).
    Also wenn du wirklich bei der malloc Version bleiben möchtest/musst solltest du Speicher mit einer akzeptablen Länge anfordern (sagen wir 100 Zeichen) und erst dann reallokieren, wenn dieser Speicher voll ist. Wenn der Speicher voll ist reallokierst du neuen Speicher und gibst als Größe die bisherige Größe * Faktor an:

    char* zeichenketteEinlesen()
    {
        size_t capacity = 100;
        size_t size = 0;
    
        char* retval = malloc( capacity +1 ); // +1 für abschließende 0
        for( ;; )
        { 
          char ch = getchar();
          if( ch == '\n' )
          {
             retval[size] = 0;
             return retval;
          }
          if( size == capacity )
          {
             capacity *= 1.5;
             retval = reinterpret_cast<char*>( realloc( retval, capacity +1 ) ); // wieder +1 für abschließende 0
          }
          retval[size++] = ch;
       }
    }
    

    Es bleibt aber noch zu sagen, dass das ein Garant für üble Fehler bleibt. Funktionen, die dynamische Objekte erzeugen und den Besitz an den Aufrufer übertragen sorgen dafür, dass einem sowas in größeren Projekten um die Ohren fliegt, weil man sich irgendwann nicht mehr über die Besitzverhältnisse im Klaren ist. Für genau solche Dinge wurde std::string gemacht.

    PS:
    Ich habe ja noch die leise Hoffnung, dass der Dozent in Wirklichkeit ein C++ Crack ist und auf RAII hinauswill. Er versucht halt nur seine Kompetenz zu verschleiern.😂



  • Und was noch niemand zur Sprache gebracht hat:
    Beim Kopieren eines Autos fliegt dir das Alles wieder um die Ohren:

    int main()
    {
        Auto a1;
        a1.setModell( zeichenketteEinlesen() );
    
        // soweit ist noch alles ok. a1.modell zeigt auf die Adresse der Zeichenkette, die in zeichenketteEinlesen einge-
        // lesen ist und gibt sie in seinem Destruktor wieder frei. Das ist ok, weil der Speicher der Zeichenkette mit malloc
        // angefordert wurde.
        Auto a2 = a1;
    
       // Boom! Beim Kopieren der Objekte werden deren member kopiert, bei Zeigern einfach der Wert. Sowohl a1.modell 
       // als auch a2.modell zeigen jetzt auf die gleiche Adresse. Im Destruktor von a2 wird a2.modell per free() frei- 
       // gegeben, soweit ist alles ok. Im Destruktor von a1 wird a1.modell ebenfalls freigegeben, aber da a1.modell und
       // a2.modell auf die gleiche Adresse zeigen wird für die gleiche Adresse 2x free() aufgerufen => Undefined behaviour.
    }
    


  • @DocShoe sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    Puuuuuh.... zeichenketteEinlesen() gewinnt auch mühelos den Worst-Perfomance Award. Du reservierst für jedes Zeichen, das du eingibst, den Speicher neu. Ja, funktioniert, und ja, das passiert wahrscheinlich schneller als jeder Benutzer tippen kann, aber es ist halt schnarchlangsam, weil Speicheranforderungen teuer sind (teuer im Sinne von kostet CPU Zeit).
    Also wenn du wirklich bei der malloc Version bleiben möchtest/musst solltest du Speicher mit einer akzeptablen Länge anfordern (sagen wir 100 Zeichen) und erst dann reallokieren, wenn dieser Speicher voll ist. Wenn der Speicher voll ist reallokierst du neuen Speicher und gibst als Größe die bisherige Größe * Faktor an:

    ja, das dachte ich mir eig. auch bei der Aufgabenstellung dass das mehr Sinn macht aber Anforderung war dass wir jedes Zeichen den Speicher neu reservieren sollten mit der Begründung man wüsste ja nicht wie viele Zeichen der User eingibt und wenn man dann Speicher für 100 Zeichen reserviert hat und dieser nur 40 eingibt man zu viel Speicher verbraucht. Was teilweise plausibel für mich als Anfänger klingt und das ja auch nur als Übung gilt für malloc/realloc und pointer.

    Es bleibt aber noch zu sagen, dass das ein Garant für üble Fehler bleibt. Funktionen, die dynamische Objekte erzeugen und den Besitz an den Aufrufer übertragen sorgen dafür, dass einem sowas in größeren Projekten um die Ohren fliegt, weil man sich irgendwann nicht mehr über die Besitzverhältnisse im Klaren ist. Für genau solche Dinge wurde std::string gemacht.

    dann will ich mal hoffen dass mein Prof langsam mal dazu kommt. 😃

    PS:
    Ich habe ja noch die leise Hoffnung, dass der Dozent in Wirklichkeit ein C++ Crack ist und auf RAII hinauswill. Er versucht halt nur seine Kompetenz zu verschleiern.😂

    ehrlich gesagt keine Ahnung ^^ vertrauen zum Prof oder den Praktikumsleitern bauen die Aufgaben jedenfalls nicht auf. 😃



  • @DocShoe also müsste im Konstruktor neuer Speicher reserviert werden in dem der Wert des Pointers geschrieben wird oder wie in einer obigen Antwort steht dass free() einfach aus dem destruktor löschen?



  • @SeppJ mhh ich denke ich spreche ihn mal darauf an. ^^ Vielleicht habe ich auch einfach einen Fehler gemacht und mal für ein paar Minuten nicht zugehört. 😃 an sich werden uns nur die Aufgaben gegeben und mMn dürftige Dokumentationen über diese Themen die wir dann zur Lösung nutzen sollen. Am Ende verschlägt es mich dann aber doch entweder in Foren wie dieses hier, zu gut und anschaulich erklärende Youtube-tutorials oder eben stundenlanges grübeln ausprobieren bis ich eine funktionierende, anscheinend halbwegs annehmbare, Lösung finde die jedes Wissen aus den Vorlesungen oder der Dokumentation über Bord wirft.



  • @wob oh ja natürlich ^^ in C++ bin ich auch schon über einfachere Methoden zur Einlesung für Zeichen gestoßen wobei ich diese noch nicht ausprobiert habe und zeichenketteEinlesen() entstammt dem ersten Semester (C), indem es wie du schon sagtest um manuelle (dynamische) Speicherverwaltung ging und Arrays.. Schleifen.. pipapow, die wir im zweiten Semester (C++) in dem ich mich jetzt befinde weiterverwenden sollten.



  • Ich finde es lustig wie hier über Code diskutiert wird, von dem wir wichtige Teile noch nichtmal gesehen haben. Wie sieht die Klasse Auto aus, was hat sie für Member? Was gibt es noch für Memberfunktionen ausser ctor und dtor und wie sind diese implementiert? Klar, man kann hier einen "educated guess" machen und wird damit vermutlich sogar richtig liegen, aber IMO naheliegend wäre erstmal den OP zu fragen.



  • @hustbaer reicht die Definition der Autoklasse dafür nicht? Wollte hier eig. nicht zu viel Code auf einmal posten, so heißt es jedenfalls im angepinnten "Du brauchst Hilfe" Thema. ^^

    aber wenn du sie sehen möchtest. die gesamte .cpp oder nur die .h?



  • @StudiengangPanik
    Die cpp reicht, wenn die Funktionen nicht im Header implementiert sind.



  • @CTecS sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    In welchen Metadateien sollte das sein, dafür gibt es die MMU die das Adressmapping macht.

    Jede Standardlibrary cached üblicherweise Speicheranforderungen und gibt sie nur nach internen Algorithmen wirklich wieder frei, in dem sie das OS unterrichtet. Das ist deutlich schneller, als alles gleich ans OS durchzureichen. Daher sind Speicherzugriffe auf bereits freigegebene Speicherbereiche möglich, die nicht zu segfaults führen. Ferner kann man bei C oder C++ nicht davon ausgehen, dass überhaupt ein OS darunter liegt, oder dass überhaupt virtuelle Adressräume genutzt werden.

    Und nein dem TO hier in jedem 2. Post nahe zu legen das er doch std::string benutzen soll, wird für ihn eine weniger Zielführende Hilfe sein. Er soll sich eben mit der Speicherverwaltung auseinander setzen.

    Das ist leider ein Dauerbrenner in diesem Forum.


  • Mod

    @StudiengangPanik sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    @DocShoe also müsste im Konstruktor neuer Speicher reserviert werden in dem der Wert des Pointers geschrieben wird oder wie in einer obigen Antwort steht dass free() einfach aus dem destruktor löschen?

    Kommt drauf an, wie nahe du dich an die Aufgabenstellung halten willst. Wie schon gesagt, merkst du, dass du "richtiges" C++ machst daran, dass du dich nicht mehr um Speicherverwaltung kümmern brauchst. Das ist das, was in der allerersten Antwort mit "Rule of zero" gemeint ist. Wenn du es also wirklich richtig machen willst, dann baust du dein gesamtes Programm total anders auf. Dann lernst du gutes C++, aber bekommst eine schlechte Note von deinem schlechten Lehrer 😕



  • @SeppJ sagte in DELETE() - Wird das Objekt wirklich gelöscht?:

    Kommt drauf an, wie nahe du dich an die Aufgabenstellung halten willst. Wie schon gesagt, merkst du, dass du "richtiges" C++ machst daran, dass du dich nicht mehr um Speicherverwaltung kümmern brauchst.

    Es kommt wie immer auf den Kontext an. I.d.R. braucht man sich nicht mehr um die Speicherverwaltung zu kümmern, aber es gibt sehr gut begründete Ausnahmen wo man es eben doch tun muss, weil es mit C++ nicht anders geht. Ein Großteil der Problematik resultiert aus Designfehler in der Standardbibliothek.



  • @StudiengangPanik Naja ich persönlich finde es z.B. doof wenn ich raten muss was ein Member wohl für einen Typ haben könnte. In dem von dir gezeigten Code muss modell fast const char* für sein, aber wie gesagt, sowas raten zu müssen finde ich unspannend.

    Ebenso die Frage welche Funktionen (speziell welche "speziellen" Funktionen wie z.B. Copy-Ctor und Assignment-Operator) hat die Klasse ausser den gezeigten noch? Vermutlich keine, aber stehen tut das auch nirgends.

    Ansonsten... wenn du noch Fragen hast... nachdem du hier ja bereits einiges an Input bekommen hast, wäre vermutlich gut wenn du deinen aktuellen Code nochmal zeigst. Damit man sieht was du jetzt wie umgesetzt hast.


Anmelden zum Antworten