"delete this" - legal?



  • Ok. Ein philosophisches Problem.



  • Wenn ihr es unbedingt wissen wollt 😛

    URL *x = URLManager->Open("bla.de");
    std::string source = x->Read();
    x->Close();
    // ist schöner als URLManager->Close(x);
    

    Gruß


  • Administrator

    volkard schrieb:

    Janjan schrieb:

    Und? Was hat das mit dem Thema zu tun? Richtig, gar nichts.

    Doch. Wenn Du ganz tief nachdenkst, kannst Du zu dem Schluß kommen, daß Close normalerweise auch bewirkt, daß das Fenster gelöscht wird. Und genau das kann man mit delete this machen. Umwege der Art, tote Fenster erst in eine Löschliste einzutragen und alle paar Sekunden die Löschliste abzuarbeiten, sind eher Umwege und sollten nicht bloß aus stilistischen Überlegungen gewählt werden, zumal man mit Zombie-Fenstern dann noch peinliche Resourcenkonflikte mit Nachfolgenden provoziert.

    Also ich schliesse oft die Fenster, frage DANACH noch Werte daraus ab und zerstöre es dann erst. Das hat den Effekt, dass der User das Gefühl hat, dass sein Interface deutlich besser reagiert. Zudem möchte ich die Möglichkeit haben, ein Fenster auf dem Stack zu erstellen, zum Beispiel für einen kurzen modalen Dialog. Genau dieses "delete this" Verhalten, welches zum Teil auch wxWidgets implementiert, finde ich katastrophal! Ich will selber die Kontrolle haben, wann ein Fenster seine Ressourcen freigibt.

    Auch musst du dann ständig mit Zeigern herumhantieren. Du kannst keine Fenster als Member einer Klasse definieren, sondern kannst in der Klasse nur Zeiger auf diese halten.

    Nein, gerade für Fenster ist sowas der völlig falsche Weg und ist nur unnötig einschränkend.

    theliquidwave schrieb:

    Wenn ihr es unbedingt wissen wollt 😛

    URL *x = URLManager->Open("bla.de");
    std::string source = x->Read();
    x->Close();
    // ist schöner als URLManager->Close(x);
    

    Gruß

    Hä? Wieso kein auto_ptr, shared_ptr oder sonst was in der Art? Wieso keine Kopie? Wieso kein Handler? Wieso überhaupt URLManager? ... Also da stellen sich eine Menge an Fragen 😃

    Grüssli



  • Weil URL eine abstrakte Klasse ist die nicht instanziert werden kann (Plugins...).

    Gruß


  • Administrator

    theliquidwave schrieb:

    Weil URL eine abstrakte Klasse ist die nicht instanziert werden kann (Plugins...).

    Und? Kannst du ein kleines bisschen genauer werden?
    Wir haben schliesslich nicht dein Wissen vom dem Konstrukt, daher muss du das schon ein wenig genauer erklären, damit wir es verstehen können. Einfach zwei Stichwörter hinzuschmeissen reicht da nicht sehr weit 😉

    Grüssli



  • Also...
    ...das ganze kommt daher, dass ich verschiedene Managerklassen habe (so mein bisheriges Konzept). Jede Managerklasse wird vom Programm instanziert und via GetProcAddress / dlsym wird dann später der Pointer zu diesen Klassen geholt (jede Instanz einer Managerklasse gibt es nur einmal im Programm, alle Plugins greifen auf diese zu). Da ich vermeiden möchte, dass ich ewig den Sourcecode mitgeben muss, habe ich alle Klassen, die man verwenden kann, abstrakt gemacht. Man kann diese also nur via Managerklasse instanzieren (lassen). So brauche ich den Sourcecode zu einer Headerdatei nicht immer preisgeben / die Pluginautoren müssen nicht ewig den ganzen Sourecode neukompilieren. Es wäre auch "dumm" wenn jeder Pluginautor den Sourcecode ändert um andere Ergebnisse zu erzielen - die Konsistenz würde einfach verloren gehen.

    All diese Probleme kann ich mit den Managerklassen lösen. Und da ich ja immerhin Speicher auf dem Heap zurückgebe, würde es einen Memoryleak geben, wenn man die Klasse nicht via Close() oder ähnlichem löscht.

    Gruß


  • Administrator

    Die Managerklasse habe ich nicht zu 100% verstanden, aber da scheint wohl einen tieferen Sinn dahinter zu stecken. Wo ich allerdings mühe habe, ist bei diesem Satz:

    Und da ich ja immerhin Speicher auf dem Heap zurückgebe, würde es einen Memoryleak geben, wenn man die Klasse nicht via Close() oder ähnlichem löscht.

    Es gibt da deutlich bessere möglichkeiten. Zum Beispiel im aktuellen Standard enthalten ist der auto_ptr .

    std::auto_ptr<int> createSomething()
    {
      return std::auto_ptr<int>(new int(3923));
    }
    
    int main()
    {
      createSomething();
      return 0;
    }
    

    Dieser Code hat kein Memory Leak. auto_ptr gehört zu den sogenannten Smart Pointern. Davon gibt es einige und auch deutlich bessere als auto_ptr . Boost bietet zum Beispiel die üblichen an:
    http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/smart_ptr.htm

    Das praktische an solchen Smart Pointern ist auch die Sicherheit bei Exceptions, da du dich dann an das RAII Konzept hälst. Nehmen wir zum Beispiel deinen Code:

    URL *x = URLManager->Open("bla.de");
    std::string source = x->Read();
    evil_function();
    x->Close();
    

    Wenn evil_function eine Exception wirft, wird nie Close aufgerufen und du hast ein Memory Leak. Mit einem Smart Pointer wäre dies nicht passiert, da er bei seiner Zerstörung automatich den Speicher freigegeben hätte. Also zum Beispiel mit auto_ptr :

    std::auto_ptr<URL> x = URLManager->Open("bla.de");
    std::string source = x->Read();
    evil_function();
    

    Dies macht keine Probleme, wenn evil_function eine Exception wirft. x wird per delete trotzdem freigegeben.

    Man kann auch eigene Smart Pointer Klassen schreiben, welche zusätzlichen spezialisierten Code bei der Zerstörung ausführen. Die Boost Smart Pointer können zum Beispiel bei der Erstellung eine Zerstörungsfunktion übernehmen, welche beim Löschen aufgerufen wird.

    Grüssli



  • Wie Genial ist das denn? Ich kannte die Teile gar nicht. Für meinen Fall scheinen die echt sinnvoll zu sein. Danke für den Tipp 👍

    Eine Frage dazu habe ich aber noch. Was ist, wenn folgendes passiert?

    std::auto_ptr<URL*> x = URLManager->Open("bla.de");
    x->Bla();
    x->Close(); // delete this
    

    Würde der auto_ptr dann nicht versuchen, ein nicht mehr existierendes Objekt zu löschen, was in einem Crash enden würde?

    Gruß


  • Administrator

    theliquidwave schrieb:

    Würde der auto_ptr dann nicht versuchen, ein nicht mehr existierendes Objekt zu löschen, was in einem Crash enden würde?

    Genau, daher weg mit der Close Funktion. Die ist ja nun unnötig, nicht? Und es ist übrigens std::auto_ptr<URL> (ohne Sternchen) 😉

    Grüssli



  • Stimmt, danke für den Hinweis.
    Das ist ja nicht gerade toll. Solch ein Fall würde dann ja auch wieder einen Leak verursachen:

    std::auto_ptr<URL> x = URLManager->Open("bla.de");
    x->Bla();
    // Instanz von x wäre ja ein Leak
    x = URLManager->Open("blubb.de");
    // ...
    

    Irgendwie ist mein Konzept nicht so robust wie ich mir das vorgestellt hatte 😃

    Gruß


  • Administrator

    theliquidwave schrieb:

    Stimmt, danke für den Hinweis.
    Das ist ja nicht gerade toll. Solch ein Fall würde dann ja auch wieder einen Leak verursachen:

    std::auto_ptr<URL> x = URLManager->Open("bla.de");
    x->Bla();
    // Instanz von x wäre ja ein Leak
    x = URLManager->Open("blubb.de");
    // ...
    

    Irgendwie ist mein Konzept nicht so robust wie ich mir das vorgestellt hatte 😃

    Ja, der auto_ptr ist nicht so ganz "smart". Dazu müsste man auto_ptr::reset verwenden.
    Wenn du einen shared_ptr nehmen würdest (ist auch in TR1 dabei, std::tr1::shared_ptr ), dann würde der Speicher auch bei einer Zuweisung freigegeben werden. Oder du bastelst dir halt einen eigenen Smart Pointer mit einem solchen Verhalten.

    Grüssli


  • Administrator

    Kam mir gerade noch in den Sinn, dass wir ja im Magazin zu den Boost Smart Pointern einen Artikel haben:
    Schlaue Zeiger - Boost Smart Pointer

    Grüssli



  • Achja stimmt, operator= überladen. Wenn man sich in die Welt der Operatoren arbeitet muss man echt viel im Auge behalten.

    Danke jedenfalls an dich!

    Edit: Boost ist mir viel zu dick. Zu viel zum herunterladen. Werde wohl was eigenes basteln.

    Gruß


  • Administrator

    theliquidwave schrieb:

    Wenn man sich in die Welt der Operatoren arbeitet muss man echt viel im Auge behalten.

    Dazu gibt es übrigens auch Artikel im Magazin:
    Überladung von Operatoren in C++ (Teil 1)
    Überladung von Operatoren in C++ (Teil 2) - Einführung in boost::operators
    Überladung von Operatoren in C++ (Teil 3) - boost::operators für Fortgeschrittene

    Falls du diese noch nicht gesehen hast 😉

    Und zu Boost:
    1. Kann man auch nur Teile davon nutzen.
    2. Kann man Boost durchaus als zweite Standardbibliothek in C++ verstehen. Auf Boost zu verzichten, nur weil es zu "dick" ist, halte ich für eine sehr schlechte Entscheidung.

    Eigene Kreationen brauchen länger und sind fehleranfälliger.

    Edit: Des Weiteren ist der Artikel oder die Artikel trotzdem interessant, da sie ja Hintergrundinformationen liefern 😉

    Grüssli



  • Dravere schrieb:

    theliquidwave schrieb:

    Stimmt, danke für den Hinweis.
    Das ist ja nicht gerade toll. Solch ein Fall würde dann ja auch wieder einen Leak verursachen:

    std::auto_ptr<URL> x = URLManager->Open("bla.de");
    x->Bla();
    // Instanz von x wäre ja ein Leak
    x = URLManager->Open("blubb.de");
    // ...
    

    Irgendwie ist mein Konzept nicht so robust wie ich mir das vorgestellt hatte 😃

    Ja, der auto_ptr ist nicht so ganz "smart". Dazu müsste man auto_ptr::reset verwenden.
    Wenn du einen shared_ptr nehmen würdest (ist auch in TR1 dabei, std::tr1::shared_ptr ), dann würde der Speicher auch bei einer Zuweisung freigegeben werden. Oder du bastelst dir halt einen eigenen Smart Pointer mit einem solchen Verhalten.

    Grüssli

    Das stimmt nicht! operator= der Klasse auto_ptr ruft delete auf. Die Dokumentation auf http://www.cplusplus.com/reference/std/memory/auto_ptr/operator=/ ist falsch!

    Lars


  • Administrator

    manni66 schrieb:

    Das stimmt nicht! operator= der Klasse auto_ptr ruft delete auf. Die Dokumentation auf http://www.cplusplus.com/reference/std/memory/auto_ptr/operator=/ ist falsch!

    Danke für den Hinweis, habe es gerade im Standard nachgeschlagen. Du hast recht, die Dokumentation ist falsch. Ich benutze halt nie std::auto_ptr , sondern immer andere Smart Pointer. Jemand sollte vielleicht mal den Autor der Dokumentation darauf aufmerksam machen 🙂

    Edit: Habe gerade dem Autor eine E-Mail zugeschickt mit dem Hinweis darauf.

    Grüssli


Anmelden zum Antworten