Singleton Frage



  • class Singleton
     {
       private:
         //Konstruktor private, damit man sich keine Instanzen holen kann.
         Singleton();
         //Den Kopierkonstruktor schützen um zu vermeiden, dass das Objekt unbeabsichtigt kopiert wird.
         Singleton(const Singleton& cc){}
    
       public:
         ~Singleton();
         static Singleton* getInstance();
     };
    
     Singleton* Singleton::getInstance()
     {
       static Singleton instance; 
       return &instance; 
     }
    

    Hab das hier bei Wikipedia gefunden. Wird beim Aufruf von getInstance() jedes mal eine neue Instanz erstellt und die alte gelöscht? 😕



  • Nein.
    Schau mal die Bedeutung von static nach. 🙂
    Ich mache das aber normalerweise dynamisch.



  • nö, ist doch static



  • static variablen werden zur laufzeit max 1x instanziert, egal wie oft die betreffende methode aufgerufen wird...

    simples bsp:

    #include <iostream>
    
    class Dummy
    { 
       static int sVar;
       int mVar;
    public:
       Dummy() : mVar(0) { }
    
       int getMemVar()
       {
          mVar++;
          return mVar; 
       }
       static int getStaticMemVar() //muss nicht static sein, ist aber ansonsten schlechter stil
       {
          sVar++;
          return sVar; 
       }
    
       static int getStaticMethodVar() //muss nicht static sein, ist aber ansonsten schlechter stil
       {
          //unterschied zu getStaticMemVar: sVar wird bereits bei Programmstart allokiert
          //            währned "var" erst bei erstem methoden aufruf allokiert wird
          //            statische member sind immer klassengobal!
          static int var=0;
          var++;
          return var; 
       }
    
       int getLocalMethodVar()
       {
          int var1=0;
          var1++;
          return var1; 
       }
    };
    
    int Dummy::sVar = 0;
    
    int main(int argc, char** argv)            
    {  
       Dummy a,b,c;  //--> output: 1 2 3
       //class member
       std::cout << a.getMemVar() <<std::endl; //-> output 1
       std::cout << b.getMemVar() <<std::endl; //-> output 1
       std::cout << c.getMemVar() <<std::endl; //-> output 1
    
       std::cout << a.getMemVar() <<std::endl; //-> output 2
       std::cout << b.getMemVar() <<std::endl; //-> output 2
       std::cout << c.getMemVar() <<std::endl; //-> output 2
    
       //static class member
       //eigentlich schreibt man bei statischen methoden: Dummy::getStaticMemVar();
       std::cout << a.getStaticMemVar() <<std::endl; //-> output 1
       std::cout << b.getStaticMemVar() <<std::endl; //-> output 2
       std::cout << c.getStaticMemVar() <<std::endl; //-> output 3
    
       std::cout << a.getStaticMemVar() <<std::endl; //-> output 4
       std::cout << b.getStaticMemVar() <<std::endl; //-> output 5
       std::cout << c.getStaticMemVar() <<std::endl; //-> output 6
    
       //static method var
       //eigentlich schreibt man bei statischen methoden: Dummy::getStaticMethodVar();
       std::cout << a.getStaticMethodVar() <<std::endl; //-> output 1
       std::cout << b.getStaticMethodVar() <<std::endl; //-> output 2
       std::cout << c.getStaticMethodVar() <<std::endl; //-> output 3
    
       std::cout << a.getStaticMethodVar() <<std::endl; //-> output 4
       std::cout << b.getStaticMethodVar() <<std::endl; //-> output 5
       std::cout << c.getStaticMethodVar() <<std::endl; //-> output 6
    
       //lokal method var
       std::cout << a.getLocalMethodVar() <<std::endl; //-> output 1
       std::cout << b.getLocalMethodVar() <<std::endl; //-> output 1
       std::cout << c.getLocalMethodVar() <<std::endl; //-> output 1
    
       std::cout << a.getLocalMethodVar() <<std::endl; //-> output 1
       std::cout << b.getLocalMethodVar() <<std::endl; //-> output 1
       std::cout << c.getLocalMethodVar() <<std::endl; //-> output 1
    }
    


  • template <class T>
    class Singleton
    {
    private:
        Singleton();
        Singleton(const Singleton&){}
        Singleton& operator=(const Singleton&) { return *this; }
    
    public:
        inline static T& instance() { static T _inst; return _inst; }
    };
    

    ?



  • @Ä(D)Evil

    Das hatte ich schon durch die Forensuche gefunden als ich eine Singleton-Template-Factory schreiben wollte. Hat leider nicht geklappt...



  • Was meinst du mit "hat nicht geklappt"?

    @topic: eine (lokale) static-Variable wird beim ersten Mal angelegt und initialisiert, wenn der Programmfluß über die Definition drübergeht - beim nächsten Durchlauf wird die Initialisierung übersprungen.
    (globale Variablen sind auch statisch - und werden vor dem Eintritt in die main() in mehr oder weniger willkürlicher Reihenfolge initialisiert)



  • Ein etwas allgemeinerer Ansatz wäre folgender:

    template <class T> 
    class CreateImplementation
    {
    public:
        static T *createNew(void)
        {
            return new T;
        }
    };
    
    template <class T,typename CreatePolicy = CreateImplementation<T> > 
    class Singleton
    {
    public:
        ~Singleton()
        {
            delete _implementation;
        }
    
        static Singleton &getInstance()
        {
    		{
    			CSingleLock lock(&_locker, TRUE);
    			if ( _instancePtr.get() == 0 ) 
    				_instancePtr = std::auto_ptr<Singleton>(new Singleton);
    		}        
    		return *_instancePtr;
        }
    
        static bool isAvailable(void)
        {      
            if ( !_instancePtr.get() ) 
    			return false;
    
            return ( instancePtr->_implementation != 0 );
        }
    
        T *operator -> ()
        {
            init();
            return _implementation;
        }
    
        void init(void)
        {
            CSingleLock lock(&_locker, TRUE);
            if ( _implementation == 0 )
    		{
    			_implementation = CreatePolicy::createNew();
    		}
        }
    
        void deinit(void)
        {
    		CSingleLock lock(&_locker, TRUE);
            if ( _implementation )
            {
    			delete _implementation;
    			_implementation = 0;
    		}
        }
    
        void restart(void)
        {
            deinit();
            init();
        }
    
    protected:
    	static CCriticalSection _locker;
    	static std::auto_ptr<Singleton>  _instancePtr;
             T *_implementation;					
    private:
        Singleton()
        {
            _implementation = 0;
        }
    
        Singleton(Singleton const& copy);
    
        void operator = (Singleton const& copy);
    };
    

    Verge



  • Ok hier mein Beispiel.

    #include <iostream>
    #include <map>
    
    //////////////////////////////////////////////////////////////////////////
    // Testklassen
    class Value
    {
    public:
    	Value()			{m_val = 0;}
    	virtual int  Get()		{return m_val;}
    protected:
    	int m_val;
    };
    
    class Value1 : public Value
    {
    public:
    	Value1()		{m_val = -1;}
    	virtual int  Get()		{return m_val;}
    protected:
    	int m_val;
    };
    
    class Value2 : public Value
    {
    public:
    	Value2()		{m_val = -2;}
    	virtual int  Get()		{return m_val;}
    protected:
    	int m_val;
    };
    
    //////////////////////////////////////////////////////////////////////////
    // 
    template<class T>
    class Singleton
    {
    public:
    	static T& Instance() {static T instance; return instance;}
    protected:
    	Singleton();
    	Singleton(const Singleton&);
    	Singleton& operator =(const Singleton&);
    };
    
    //////////////////////////////////////////////////////////////////////////
    // 
    class Factory : public Singleton<Factory>
    {
    public:
    
    	Value* Create(int typ)
    	{
    		Value* temp = NULL;		
    		switch(typ)
    		{
    			case 1:
    			{
    				Value1* val = new Value1;
    				m_instanceList.insert( m_instanceList.end(), std::pair<Value*, int>(val,0) );
    				temp = val;
    				break;
    			}
    			case 2:
    			{
    				Value2* val = new Value2;
    				m_instanceList.insert( m_instanceList.end(), std::pair<Value*, int>(val,0) );
    				temp = val;
    				break;
    			}
    		}
    		return temp;
    	}
    
    	void Destroy(Value* elem)
    	{
    		std::map<Value*, int>::iterator iter;
    		iter = m_instanceList.find(elem);
    		if(iter != m_instanceList.end())
    		{
    			delete iter->first;
    			m_instanceList.erase(iter);
    		}
    	}
    
    private:
    	std::map<Value*, int> m_instanceList;	// int wert wird nicht ausgewertet, dient nur als dummy
    };
    
    int main(int argc, char* argv[])
    {
    	Value* val1 = Factory::Instance().Create(1);
    	Value* val2 = Factory::Instance().Create(1);
    
    	std::cout<<val1->Get()<<std::endl;
    	std::cout<<val2->Get()<<std::endl;
    
    	Factory::Instance().Destroy(val1);
    	Factory::Instance().Destroy(val2);
    
    	int q;
    	std::cin>>q;
    
    	return 0;
    }
    

    Ich bekomme hier beim VC 6 einen Linker Fehler und sehr viele seltsame Warnungen:

    templatetest.obj : error LNK2001: Nichtaufgeloestes externes Symbol "protected: __thiscall Singleton<class Factory>::Singleton<class Factory>(void)" (??0?$Singleton@VFactory@@@@IAE@XZ)
    Debug/templatetest.exe : fatal error LNK1120: 1 unaufgeloeste externe Verweise
    
    c:\Programme\Microsoft Visual Studio\VC98\INCLUDE\xtree(200) : warning C4786: '?rbegin@?$_Tree@PAVValue@@U?$pair@QAVValue@@H@std@@U_Kfn@?$map@PAVValue@@HU?$less@PAVValue@@@std@@V?$allocator@H@3@@3@U?$less@PAVValue@@@3@V?$allocator@H@3@@std@@QAE?AV?$
    reverse_bidirectional_iterator@Viterator@?$_Tree@PAVValue@@U?$pair@QAVValue@@H@std@@U_Kfn@?$map@PAVValue@@HU?$less@PAVValue@@@std@@V?$allocator@H@3@@3@U?$less@PAVValue@@@3@V?$allocator@H@3@@std@@U?$pair@QAVValue@@H@3@AAU43@PAU43@H@2@XZ' : Bezeichner
     wurde auf '255' Zeichen in den Browser-Informationen reduziert
            c:\Programme\Microsoft Visual Studio\VC98\INCLUDE\map(46) : Siehe Verweis auf Instantiierung der kompilierten Klassenvorlage 'std::_Tree<class Value *,struct std::pair<class Value * const,int>,struct std::map<class Value *,int,struct std::le
    ss<class Value *>,class std::allocator<int> >::_Kfn,struct std::less<class Value *>,class std::allocator<int> >'
            C:\templatetest\templatetest.cpp(109) : Siehe Verweis auf Instantiierung der kompilierten Klassenvorlage 'std::map<class Value *,int,struct std::less<class Value *>,class std::allocator<int> >'
    

    Laut MSDN sind meine Symbolnamen zu lang ( 😕 ). Das scheint nicht soo schlimm zu sein. Ich möchte aber trozdem nichts benutzen was so viele warnungen erzeugt.

    Den Linkerfehler konnte ich nicht beseitigen... Keine Ahnung woran das liegen kann. Der ganze code steht in einer einzigen cpp Datei.



  • SingletonAnfänger schrieb:

    Ich möchte aber trozdem nichts benutzen was so viele warnungen erzeugt.

    Zu diesem Zwecke empfehle ich:: Visual C++ 2005 Express Edition 😃



  • /////////////////////////////////////////////////////////////////////////
    //
    template<class T>
    class Singleton
    {
    public:
        static T& Instance() {static T instance; return instance;}
    protected:
        Singleton();
        Singleton(const Singleton&);
        Singleton& operator =(const Singleton&);
    };
    

    Du hast deinem Singleton keinen Konstruktor definiert, nur deklariert. Ist zwar richtig dass der nur protected ist, aber es muss ihn trotzdem geben, sonst kannst du kein Objekt davon erstellen. nichtmal das einzige. Mit static T instance; versuchst du das aber, und der Compiler bzw. Linker meckert zu recht dass er nicht weiss wie er das bewerkstelligen soll.



  • pumuckl schrieb:

    Du hast deinem Singleton keinen Konstruktor definiert, nur deklariert.

    Boar ich wusste das es irgend so ein sinnloser Schusselfehler ist. Danke dir 👍

    LordJaxom schrieb:

    SingletonAnfänger schrieb:

    Ich möchte aber trozdem nichts benutzen was so viele warnungen erzeugt.

    Zu diesem Zwecke empfehle ich:: Visual C++ 2005 Express Edition 😃

    Mal gucken ob die Warnungen beim eVC auch noch auftauchen. Vieleicht lohnt es sich ja wirklich auf die VS 05er Express Version um zu steigen.

    Aber mal was anderes. Ich schreibe hier so etwas wie einen Serverdienst. Der soll verschiedene Nachrichten empfangen und diese an diverse Threads zur Verarbeitung verteilen. Als Datenstruktur nehme ich dafür FIFOs.

    Was wäre denn jetzt Designtechnisch besser (und schneller).
    (1) Das Nachrichtenobjekt jedesmal kopieren wenn es an eine FIFO rangehängt wird.
    (2)Oder sollte ich doch lieber nur deren Zeiger in den FIFOs verwalten?

    Für 2. bräuchte ich halt meine Singleton-Template-Factory um die Objekte irgendwo zentral zu verwalten.


Anmelden zum Antworten