Problem mit Singleton: "Kein Zugriff auf private Member, dessen Deklaration in der ...-Klasse erfolgte"



  • Am besten beides, dh wenn ich das "neu initialiseren" will und halt bei Programmende den Speicher freigeben ...



  • Nowis schrieb:

    Am besten beides, dh wenn ich das "neu initialiseren" will und halt bei Programmende den Speicher freigeben ...

    Dann müsste dein Destroy so aussehen:

    static void Destroy()
        {
            delete singleton;
            singleton = 0;
        }
    

    Am Programmende musst du Application::Destroy() zu Fuß ausführen, oder immer dann, wenn du das Singleton neu initialisieren möchtest. Im Detruktor wird die Funktion aber nicht aufgerufen.

    Ich glaube aber noch ein anderes Problem zu sehen: die eigentliche Singeltonvariable wird mit

    template <class T>
    T* Singleton<T>::singleton = NULL;
    

    im Header Singleton.hpp definiert. Meiner Meinung nach erzeugst du damit mehrere Versionen in den CPPs, in denen du Applikation benutzt => ODR (one definition rule) verletzt => undefiniertes Verhalten. Ich bin mir aber nicht sicher, ob das wirklich falsch ist.

    Lars



  • Ok, die Destroy-Methode ist geändert ...

    Aber das mit dem manuell Aufrufen ist schon ein bisschen umständlich, ich will ja später mehrere Klassen von Singleton erben lassen und das dann von allen selber aufrufen 👎



  • Nowis schrieb:

    Ok, die Destroy-Methode ist geändert ...

    Aber das mit dem manuell Aufrufen ist schon ein bisschen umständlich, ich will ja später mehrere Klassen von Singleton erben lassen und das dann von allen selber aufrufen 👎

    Naja, du kannst das Löschen am Ende ja auch sein lassen. Das macht das Betriebssystem sowieso. Oder du benutzt statt T* für die Membervariable singleton einen std::auto_ptr<T>. Dann musst du nichts manuell machen.

    Lars



  • Warum eigentlich den "Umweg" über ein Template und nicht einfach public geerbt?



  • Warum eigentlich überhaupt erben? Damit deine Klasse ein Singleton ist, musst du Konstruktoren und op= sowieso private machen, auch mit dem Template.
    Dann implementierst du eine einzige statische getter-Funktion im Meyer-Singleton-Stil, und alles ist paletti. Das sind pro Singleton 2 relevante Zeilen zusätzlich. Und wenn das bei dir ein untragbarer Mehraufwand ist, machst du eh was falsch, wer so viele Singletonklassen braucht gehört auf den Mond katapultiert 😃



  • l'abra d'or schrieb:

    Warum eigentlich überhaupt erben?

    Singleton-Vererbung ist C++-Anfänger-Stil, das sieht man leider in jedem schlechten Code.



  • Vielen Dank für die vielen Antworten,

    ich wollte mir halt eine einzige Klasse erstellen, von der ich nur noch erben muss, aber im Prinzip habt ihr recht, um ein Singleton zu erstellen braucht man ja nicht viel, das kann man dann auch jedesmal wieder machen, und die 3 Zeilen mehr Code machens dann auch nich mehr aus.

    Ich werde euren Rat beherzigen und die Singleton Klasse über Bord werfen.

    Baut man eigentlich bei einem Singleton einen Destruktor ein?, oder benutzt man hier nur eine Destroy / Delete-Methode?



  • Und gleich noch eine Frage hinterher:

    Wie müsste ich eine Singleton-Klasse aufbauen, die mit einem auto_ptr funktioniert?



  • Baut man eigentlich bei einem Singleton einen Destruktor ein?, oder benutzt man hier nur eine Destroy / Delete-Methode?

    Destruktor und Destroy sind verschiedene Sachen. Destroy soll das statische Objekt zerstören (mit delete), der Destruktor kümmert sich darum, dass beim Zerstören auch brav alle Member zerstört werden und der Speicher bereinigt wird.

    Du brauchst also auch bei einem Singleton einen Destruktor, wenn du z.B. dynamisch alloziierte Member hast, oder sonst was aufgeräumt werden muss.

    Wie müsste ich eine Singleton-Klasse aufbauen, die mit einem auto_ptr funktioniert?

    Das brauchst du eigentlich auch nicht. Ich hab oben schon den "Meyer Singleton" erwähnt:

    #include <vector>
    #include <iostream>
    
    struct Item {
        Item(int val)
         : value(val)
        {}
        int value;
    };
    
    class Manager {
        Manager() { std::cout << "Konstruktor" << std::endl; }
        ~Manager() { std::cout << "Destruktor" << std::endl; }
        Manager(const Manager&);
        Manager& operator=(const Manager&);
    
        std::vector<Item> items;
    
    public:
        static Manager& get() {
            static Manager m;
            return m;
        }
    
        void manage(const Item& i) {
            items.push_back(i);
        }
    
        const std::vector<Item>& managedItems() const {
            return items;
        }
    };
    
    int main() {
        Manager::get().manage(Item(10));
        Manager::get().manage(Item(20));
    
        const std::vector<Item>& items = Manager::get().managedItems();
        for(size_t i=0; i<items.size(); ++i)
            std::cout << items[i].value << " ";
        std::cout << std::endl;
    }
    

    Schau dir die get()-Funktion an. Auch den Destruktor kannst du private machen, damit niemand auf dumme Gedanken kommt :p



  • Ok, vielen Dank an alle die geantwortet haben, ich werde das in Zukunft beherzigen.

    Alle meine Fragen sind jetzt beantwortet ....

    CLOSED


Anmelden zum Antworten