singelton und destruktor?



  • Also Andrei Alexandrescu schlägt in "Modern C++ Design: Generic Programming and Design Patterns Applied" vor, in Fällen, wo das Singlton u.U. von z.B. anderen statitischen Objekten zum Aufräumen oder für andere Zwecke benötigt wird vor, entweder die Persistenz mit Prioritäten zu sichern, oder das Singleton wiederauferstehend gesatalten. Also es so zu bauen, dass es zwar zu jeder beliebigen Zeit zerstört werden kann, es aber wieder aufersteht, wenn es nach seiner Zerstörung doch noch einmal benötigt wird. Als Beispiel nimmet ein ein Logging-Singleton wo fehler von anderen Singletons beim Abräumen geloggt werden.
    Insgesamt gibt es aber kein "Universal-Singleton", mit dem alle Probleme auf einmal gelöst werden können.



  • Simon2 schrieb:

    äh ... was spricht gegen meinen "Abräumer" ?

    Der ist natürlich als eigenes Micro-Design Pattern klasse.

    Konrad Rudolph schrieb:

    Okay, welchen Sinn hat das mit dem Zeiger eigentlich? Wieso verwendest Du nicht folgenden Code:

    static singleton& instance() {
        static singleton the_instance;
        return the_instance;
    }
    

    Das geht bestimmt oftmals gut - aber "lazy creation" kann man damit halt nicht machen (nur, für den Fall, dass man es braucht).

    Meine Variante *ist* lazy. Insbesondere wird nie eine Instanz von 'singleton' erstellt, es sei denn, man ruft 'instance' auf.

    und wie sieht's aus, wenn man ein parametrisiertes instance() anbieten möchte ? (wobei das Schwierigkeiten beim 2. Aufruf bereitet)

    Stimmt, das geht dann nicht mehr. In diesem Fall hat man aber eh keinen reinen Singleton mehr und benötigt irgendeine Art Factory.



  • Simon2 schrieb:

    Das geht bestimmt oftmals gut - aber "lazy creation" kann man damit halt nicht machen (nur, für den Fall, dass man es braucht).
    und wie sieht's aus, wenn man ein parametrisiertes instance() anbieten möchte ? (wobei das Schwierigkeiten beim 2. Aufruf bereitet)

    Wie "Lazy" soll denn das Erzeugen noch werden? 🙂



  • Simon2 schrieb:

    hmm vlt. schrieb:

    Tachyon hats schon gesagt. Da braucht man kein Assembler.

    Habe ich behauptet, dass man zur Lösung dieses Problems Assembler braucht ?
    Übrigens: Wenn Du keine blöden Antworten haben möchtest, solltest Du evtl. dazu übergehen, Deine Standpunkte verständlich darzulegen.
    Wen jemand in "Ein-Satz-Statements" kommuniziert, ist nicht immer die Umwelt schuld, wenn sie einen mißversteht.

    Warum hast du denn überhaupt Assembler erwähnt? Das hat schon da keinen Sinn gemacht, wo du es gepostet hast, weil es nix mit dem Thema zu tun hat, sondern einfach nur danach aussieht.



  • hmm vlt. schrieb:

    ...Warum hast du denn überhaupt Assembler erwähnt? ...

    Nun, erstmal war es "augenwinkernd" (habe ich ja sogar mit einem passenden Smilie).
    Und zum zweiten hattest Du als einziges Argument gegen meinen Vorschlag einen Mangel an Kontrolle gebracht. Mit der Erwähnung von Assembler (als Beispiel absurder Übertreibung) wollte ich das Augenmerk darauf lenken, dass "Kontrolle haben wollen" nicht das einzige Kriterium für oder gegen eine Programmiertechnik sein kann.
    (eben weil jemandem, für den das das einzige Kriterium wäre, höchstens Assembler übrig bliebe ...)
    Da allerdings von Dir kein anderes erwähnt wurde, hoffte ich da auch mehr (ein Wunsch, der allerdings bis jetzt unerfüllt ist).

    Ich hoffe, das ist jetzt klarer geworden und wir können uns wieder der eigentlichen Frage zuwenden.

    Gruß,

    Simon2.



  • Konrad Rudolph schrieb:

    ...
    Meine Variante *ist* lazy. Insbesondere wird nie eine Instanz von 'singleton' erstellt, es sei denn, man ruft 'instance' auf....

    Stimmt natürlich ! Mein Fehler !
    Ist Deine Variante eigentlich bzgl. der von Tachyon angesprochenen Abhängigkeiten zuverlässiger ?
    Eigentlich auch nicht, oder ?

    Konrad Rudolph schrieb:

    ...

    und wie sieht's aus, wenn man ein parametrisiertes instance() anbieten möchte ? (wobei das Schwierigkeiten beim 2. Aufruf bereitet)

    Stimmt, das geht dann nicht mehr. In diesem Fall hat man aber eh keinen reinen Singleton mehr und benötigt irgendeine Art Factory.

    Ja - ich war ja von dem Argument sowieso nicht sooo überzeugt.

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Konrad Rudolph schrieb:

    ...
    Meine Variante *ist* lazy. Insbesondere wird nie eine Instanz von 'singleton' erstellt, es sei denn, man ruft 'instance' auf....

    Stimmt natürlich ! Mein Fehler !
    Ist Deine Variante eigentlich bzgl. der von Tachyon angesprochenen Abhängigkeiten zuverlässiger ?
    Eigentlich auch nicht, oder ?

    Da die Aufräum-Reihenfolge statischer lokaler Objekte nicht definiert ist, wohl nicht (→3.6.3.2).



  • Simon2 schrieb:

    Wie wär's mit einem statischen "Aufräumer" ?

    struct Aufräumer;
    class Singleton
    {
    // ... Dein Code ...
    
    // zusätzlich:
       protected:
         ~Singleton() {} // Nicht unwichtig ! Schließlich soll kein "Nutzer" das Teil abräumen können
       friend Aufräumer;
    };
    
    struct Aufräumer {
       ~Aufräumer() { delete Singleton::instanz; }
    }
    
    static Aufräumer a;
    

    Bei static Objekten sorgte IIRC der Compiler dafür, dass sie ganz am Ende abgeräumt werden (wenn überhaupt unwinding stattfindet).

    Und wie siehts mit der Reihenfolge der Destruktion von globalen static Objekten aus ?



  • Konrad Rudolph schrieb:

    Simon2 schrieb:

    Konrad Rudolph schrieb:

    ...
    Meine Variante *ist* lazy. Insbesondere wird nie eine Instanz von 'singleton' erstellt, es sei denn, man ruft 'instance' auf....

    Stimmt natürlich ! Mein Fehler !
    Ist Deine Variante eigentlich bzgl. der von Tachyon angesprochenen Abhängigkeiten zuverlässiger ?
    Eigentlich auch nicht, oder ?

    Da die Aufräum-Reihenfolge statischer lokaler Objekte nicht definiert ist, wohl nicht (→3.6.3.2).

    OK - hat mich nur interessiert, ob das auch anders ist als bei globalen.

    Danke,

    Simon2.



  • KasF schrieb:

    ...Und wie siehts mit der Reihenfolge der Destruktion von globalen static Objekten aus ?

    Wie schon oben erwähnt: Undefiniert.

    Gruß,

    Simon2.



  • KasF schrieb:

    Simon2 schrieb:

    Wie wär's mit einem statischen "Aufräumer" ?

    struct Aufräumer;
    class Singleton
    {
    // ... Dein Code ...
    
    // zusätzlich:
       protected:
         ~Singleton() {} // Nicht unwichtig ! Schließlich soll kein "Nutzer" das Teil abräumen können
       friend Aufräumer;
    };
    
    struct Aufräumer {
       ~Aufräumer() { delete Singleton::instanz; }
    }
    
    static Aufräumer a;
    

    Bei static Objekten sorgte IIRC der Compiler dafür, dass sie ganz am Ende abgeräumt werden (wenn überhaupt unwinding stattfindet).

    Und wie siehts mit der Reihenfolge der Destruktion von globalen static Objekten aus ?

    Mal ganz davon abgesehen, dass dies nur eine komplizierte Variante vom klassischen Meyers Singleton ist:

    Singleton& Singleton::instance( )
    {
        static Singleton singleton;
        return singleton;
    }
    

    Es macht genau das gleiche, und hat genau das gleiche Problem: Es kann bereits an Stellen zerstört worden sein, an denen es noch benötigt wird.



  • Simon2 schrieb:

    Konrad Rudolph schrieb:

    Da die Aufräum-Reihenfolge statischer lokaler Objekte nicht definiert ist, wohl nicht (→3.6.3.2).

    OK - hat mich nur interessiert, ob das auch anders ist als bei globalen.

    Ist es, denn bei globalen Objekten ist die Aufräumreihenfolge definiert, auch wenn das meistens nicht viel nützen wird: laut Standard müssen globale Objekte mit statischem Speicher am Ende von 'main' in umgekehrter Initialisierungsreihenfolge zerstört werden. Bei lokalen statischen Objekten gibt es eben selbst diese Garantie nicht mehr.


  • Mod

    KasF schrieb:

    ...Und wie siehts mit der Reihenfolge der Destruktion von globalen static Objekten aus ?

    Die Zerstörung erfolgt in umgekehrter Reihenfolge der Beendigung ihrer Konstruktion. Es besteht dabei kein Unterschied zwischen lokalen statischen Objekten und Namensraumobjekten.



  • Naja, ein globales Singleton ist ja auch kein Problem, das dürfte ja aber trotzdem nichts ändern.



  • Konrad Rudolph schrieb:

    Ist es, denn bei globalen Objekten ist die Aufräumreihenfolge definiert, auch wenn das meistens nicht viel nützen wird: laut Standard müssen globale Objekte mit statischem Speicher am Ende von 'main' in umgekehrter Initialisierungsreihenfolge zerstört werden. Bei lokalen statischen Objekten gibt es eben selbst diese Garantie nicht mehr.

    Was dennoch nicht viel nützt weil die Reihenfolge in der statische globale Objekte angelegt werden nicht definiert ist.



  • asc schrieb:

    Konrad Rudolph schrieb:

    Ist es, denn bei globalen Objekten ist die Aufräumreihenfolge definiert, auch wenn das meistens nicht viel nützen wird: laut Standard müssen globale Objekte mit statischem Speicher am Ende von 'main' in umgekehrter Initialisierungsreihenfolge zerstört werden. Bei lokalen statischen Objekten gibt es eben selbst diese Garantie nicht mehr.

    Was dennoch nicht viel nützt weil die Reihenfolge in der statische globale Objekte angelegt werden nicht definiert ist.

    Fassen wir zusammen: Es nützt nicht viel, dennoch nützt es nicht viel? 😉



  • asc schrieb:

    Was dennoch nicht viel nützt weil die Reihenfolge in der statische globale Objekte angelegt werden nicht definiert ist.

    Innerhalb einer Übersetzungseinheit schon. Wenn es mehrere sind, dann ist unspezifiziert.


  • Mod

    Konrad Rudolph schrieb:

    Bei lokalen statischen Objekten gibt es eben selbst diese Garantie nicht mehr.

    Wie liest du dann 3.6.3/1 Satz 1 und 2?



  • Umm mal auf die Ausgangsfrage zurückzukommen:
    Eigentlich sollte man allokierte Ressourcen auch wieder freigeben. Bei Speicher ist es zwar in der Regel unproblematisch, wenn man es nicht tut, aber bei anderen Ressourcen ist es zwingend erforderlich, sie wieder freizugeben.

    Es gibt nun verschiedene Möglichkeiten, dies zu realisieren, wobei die Wahl davon abhängt, wie lange das Singleton existieren muss.

    Wenn klar ist, dass es zum Zeitpunkt der Terminierung der Applikation keine Zugriffe auf das Singleton mehr geben wird bzw. wenn nur nicht-statische/nicht-globale Funktionen auf das Singleton zugreifen, kann man das klassische Meyer-Singleton benutzen. Also eine Referenz auf eine funktionsolkale, statische Instanz des Singleton-Objekts zurückgeben.

    Ist dies nicht der Fall, muss man irgendwie dafür sorgen, dass das Singleton existent bleibt, wenn die globalen/lokalen statischen Funktionen darauf zugreifen.
    Entweder, man macht es so, dass das Objekt zwar zerstört wird, es aber automatisch reinstantiiert wird, wenn es nochmal benötigt wird (gemeinhin als Phoenix Singleton bezeichnet), oder mal gibt für seine globalen Objekte und das Singleton eine expliziete Zerstörungsreihenfolge an.



  • camper schrieb:

    Konrad Rudolph schrieb:

    Bei lokalen statischen Objekten gibt es eben selbst diese Garantie nicht mehr.

    Wie liest du dann 3.6.3/1 Satz 1 und 2?

    Nirgends, ich hatte „at block scope“ in Satz 1 überlesen.


Anmelden zum Antworten