Zeiger = 0;



  • Im russischen gibt es solch ein Sprichwort: "jeder spricht darüber, was ihm weh tut" und antwortet nicht auf die Frage des anderen.

    Meine Frage war, wie ich das ohne diesen ganzen Schnick-Schnack ganz simpel geregelt bekomme.

    oben habe ich ein korrigiertes Code-Stück aufgetipt wenn ihr das noch nicht bemerkt habt:

    class Data; 
    
    class Pointer 
    { 
    private: 
    
        Data* data 
    
    public: 
    
        Pointer(Data& d) 
        { 
            data = new Data(d); 
        } 
    
        free_memory() 
        { 
            delete data; 
        } 
    }; 
    
    int main(void) 
    { 
        Data d; 
        Pointer* p = new Pointer(d); 
    
        p->free_memory(); 
    
        return 0; 
    }
    

    Beide Pointer werden ordnungsgemäß gelöscht und deren Inhalt am Ende geleert, müsste doch korrekt funktionieren?



  • RussianTux schrieb:

    Beide Pointer werden ordnungsgemäß gelöscht und deren Inhalt am Ende geleert, müsste doch korrekt funktionieren?

    Ich sehe da zwei new und nur ein delete .



  • @RussianTux: Du baust dir doch gerade selbst einen Smartpointer nach, nur viel viel schlechter. Das ist kein Schnick-Schnack, vertrau doch den erfahrenen Leuten hier. Du löschst das Pointer-Objekt nicht und dadurch, dass du free_memory aufrufen musst, ist das ganze auch nicht Exception-save.



  • TyRoXx schrieb:

    RussianTux schrieb:

    Beide Pointer werden ordnungsgemäß gelöscht und deren Inhalt am Ende geleert, müsste doch korrekt funktionieren?

    Ich sehe da zwei new und nur ein delete .

    Ups, mein Fehler, korrigiere ich mal eben:

    class Data; 
    
    class Pointer 
    { 
    private: 
    
        Data* data 
    
    public: 
    
        Pointer(Data& d) 
        { 
            data = new Data(d); 
        } 
    
        free_memory() 
        { 
            delete data; 
        } 
    }; 
    
    int main(void) 
    { 
        Data d; 
        Pointer* p = new Pointer(d); 
    
        p->free_memory(); 
        delete p;
    
        return 0; 
    }
    


  • Was bringt dir die Pointer -Klasse, wenn sie nicht automatisch aufräumt?

    Wenn man free_memory() explizit aufrufen muss, kann man genauso gut delete verwenden. Dadurch gewinnst du absolut nichts.



  • Die ordentliche Lösung ohne Schnickschnak wäre std::unique_ptr.



  • Nexus schrieb:

    Was bringt dir die Pointer -Klasse, wenn sie nicht automatisch aufräumt?

    Wenn man free_memory() explizit aufrufen muss, kann man genauso gut delete verwenden. Dadurch gewinnst du absolut nichts.

    а мне блеать нахуй не надо автоматики тупорылые немецкие сущности

    Ich habe nie erwähnt dass ich Automatik brauche?!

    Der Aufruf von free_memory() sollte den Konstruktor von 'Data d' aufrufen und den Speicher bereinigen?!



  • RussianTux schrieb:

    Ich habe nie erwähnt dass ich Automatik brauche?!

    Ok, dann bringt die ganze Pointer -Klasse erst recht nichts.

    RussianTux schrieb:

    Der Aufruf von free_memory() sollte den Konstruktor von 'Data d' aufrufen und den Speicher bereinigen?!

    Du meinst Destruktor. Aber dafür reicht auch delete , dann hast du wenigstens nicht diese willkürliche Asymmetrie zwischen Anforderung und Freigabe.



  • RussianTux schrieb:

    Der Aufruf von free_memory() sollte den Konstruktor von 'Data d' aufrufen und den Speicher bereinigen?!

    Das ist aber keine ordentliche Lösung. Das versuchen wir dir hier nun schon seit vielen Seiten klarzumachen...

    Ordentliche Lösung: Verwend std::unique_ptr oder etwas vergleichbares. Schreib es selbst wenn du unbedingt willst, aber verwend RAII.



  • Nexus schrieb:

    RussianTux schrieb:

    Ich habe nie erwähnt dass ich Automatik brauche?!

    Ok, dann bringt die ganze Pointer -Klasse erst recht nichts.

    Ganz genau, nix Automatiko, nur eine Simple Klasse, die man als Pointer verwendet, welche einen Pointer mit 1 element vom Typ 'Data' beherbergt.

    RussianTux schrieb:

    Der Aufruf von free_memory() sollte den Konstruktor von 'Data d' aufrufen und den Speicher bereinigen?!

    Du meinst Destruktor. Aber dafür reicht auch delete , dann hast du wenigstens nicht diese willkürliche Asymmetrie zwischen Anforderung und Freigabe.

    Jap, sorry, Destruktor war gemeint, klar reicht hier auch ein delete aus, ala

    Pointer* p = new Pointer(Data d);
    delete p->data;
    delete p;
    

    Die Funktion dient nur als eine Art Setter für das private Feldelement 'data'

    Oder hast du hast anderes gemeint? 🙂



  • wtf?

    std::unique_ptr<Data> p(new Data());
    

    done



  • dot schrieb:

    wtf?

    std::unique_ptr<Data> p(new Data());
    

    done

    Warum ratet ihr denn alle von der manuellen Verwendung delete's ab? delete ist doch nur ein Operator der den Destruktor eines Objekts aufruft, welcher es zerstört, oder ist er einfach nur so in C++ eingebunden, um den Quell-Code schöner zu machen?!

    Bitte entschuldigt mich wenn ich mit dieser - von euch aus gesehen - Dummheit rumspamme, aber ich erkenne den Sinn eurer Ratschläge nicht, warum soll delete seine Arbeit nicht erfüllen können?

    Bitte erleuchtet doch meine dummen Gedanken



  • RussianTux schrieb:

    Warum ratet ihr denn alle von der manuellen Verwendung delete's ab?

    Weil es fehleranfällig ist und den Code komplizierter macht. Wenn du mehrere Return-Pfade oder sogar Exceptions hast und alles korrekt freigeben musst, wird das schnell die Hölle.

    RAII ist die Lösung, um Ressourcen sicher und sauber freizugeben. std::unique_ptr zum Beispiel implementiert simples RAII für Zeiger.

    RussianTux schrieb:

    oder ist er einfach nur so in C++ eingebunden, um den Quell-Code schöner zu machen?!

    Ne, er wird auf Low-Level-Ebene gebraucht. Eben um solche Dinge wie Smart-Pointer zu schreiben. Aber der durchschnittliche Benutzer implementiert solche Funktionalität nicht, und kommt entsprechend gut ohne delete aus.



  • [quote="Nexus"]

    RussianTux schrieb:

    Warum ratet ihr denn alle von der manuellen Verwendung delete's ab?

    Weil es fehleranfällig ist und den Code komplizierter macht. Wenn du mehrere Return-Pfade oder sogar Exceptions hast und alles korrekt freigeben musst, wird das schnell die Hölle.

    Letzte Frage bezüglich delete: Welche Fehler kann dieser Operator denn genau verursachen? Worin besteht die Gefahr der Nutzung dieses Operators?



  • Dass man es vergisst (zu jedem new gehört ein delete), und man sich dadurch ein Speicherleck einfängt.
    Dass man ein delete macht, den Zeiger aber später noch braucht, man auf "!zeiger" prüft - dummerweise vergessen hat zeiger nach dem delete auf 0 zu setzen.
    Dass Zeiger herumgereicht werden, auch in anderen Objekten gespeichert, und man ein delete auf den Zeiger macht, obwohl das Objekt dahinter noch anderswo benötigt wird (Anwendungsfall shared_pointer).
    Usw.

    Halt alles was durch Nachlässigkeit, Faulheit, Unwissenheit, ausreichend hohe Komplexität, schlecht stehende Sterne, ... verursacht werden kann.
    Es hat schon seinen Grund, warum sich Leute Gedanken über generische schlaue Zeiger machen.



  • Ich hab eine kleine Aufgabe für dich:

    void foo()
    {
      int* x = new int;
    
      if (hell_yeah())
        goto get_santa;
    
      // ...
    
    a:
    
      if (bla)
        return;
    
      if (solo)
        throw std::runtime_error("i have a bad feeling about this");
    
      // ...
    
      return;
    
    get_santa:
    
      if (hohoho())
      {
        x = new int(42);
        goto a;
      }
    
    }
    

    Füge in diese Funktion alle deletes ein, die notwendig sind, damit der int, auf den x zeigt, immer und unter allen Umständen freigegeben wird.



  • dot schrieb:

    Füge in diese Funktion alle deletes ein die notwendig sind, damit der int auf den x zeigt immer und unter allen Umständen freigegeben wird.

    Füge in diesen Satz alle Kommas ein, die notwendig sind, damit er immer verstanden wird und korrekt ist.

    SCNR 😃



  • check (hoffentlich richtig) 😉



  • Perfekt 🙂



  • dot schrieb:

    Ich hab eine kleine Aufgabe für dich:

    void foo()
    {
      int* x = new int;
    
      if (hell_yeah())
        goto get_santa;
    
      // ...
    
    a:
    
      if (bla)
        return;
    
      if (solo)
        throw std::runtime_error("i have a bad feeling about this");
    
      // ...
    
      return;
    
    get_santa:
    
      if (hohoho())
      {
        x = new int(42);
        goto a;
      }
    
    }
    

    Füge in diese Funktion alle deletes ein, die notwendig sind, damit der int, auf den x zeigt, immer und unter allen Umständen freigegeben wird.

    void foo()
    {
      int* x = new int;
    
      if (hell_yeah())
        goto get_santa;
    
      // ...
    
    a:
    
      delete x;///Erstes
    
      if (bla)
        return;
    
      if (solo)
        throw std::runtime_error("i have a bad feeling about this");
    
      // ...
    
      return;
    
    get_santa:
    
      if (hohoho())
      {
        delete x;///Drittes
        x = new int(42);
        goto a;
      }
    
      delete x;///Zweites
    
    }
    

    Dot, so richtig?

    @Kellerautomat: SCNR 😃 jetzt aber. Versprochen.


Anmelden zum Antworten