Probleme mit Librarys in Chatprogram



  • Hallo zusammen!

    ich habe in letzter Zeit ein einfaches Chatprogramm geschrieben, dass auf mehreren Projektes aufbaut:

    ->Shared
    ->ServerBase
    ->ServerGUI
    ->ClientBase
    ->ClientGUI

    Erst hatte ich es so geplant, dass nur die "Base" projekte als lib compiled werden, Shared header allerdings includieren, jedoch nicht die shared.lib. Die GUI projekte sollten dann die base.lib includieren, um das ganze variabler zu halten.
    Wie auch immer, das hat nicht ganz funktioniert und jetzt "erbt" jedes projekt die lib des übergeordneten.
    Compilen tut alles fein, bis auf einen Fehler

    error LNK2001: Nicht aufgelöstes externes Symbol ""private: static class Chat::ACClient * Chat::Singleton<class Chat::ACClient>::m_instance" (?m_instance@?$Singleton@VACClient@Chat@@@Chat@@0PAVACClient@2@A)".
    

    Ich bin schon alle "standard" methoden die ich so kannte durchgegangen um den LNK fehler zu beheben, allerdings hat nichts geholfen.

    hat einer eine idee woran das liegen könnte, oder tipps wie ich das projekt besser ordnen sollte?

    Mfg, Xaser



  • hast du die m_instance variable denn auch definiert? Es reicht nicht aus, sie in der Klassendefinition zu deklarieren. Es sieht so aus, als wäre es ein statisches member eines Templates, also muss die Definition in den Header:

    //test.h
    template <class T>
    class A
    {
      static int i; //nur deklaration!
    };
    
    template <class T>
    A<T>::int i; //definition!
    

    Bei Bedarf kanst du die statische Variable auch initialisieren.

    Ich würd allerdings die Singletoninstanz als statische Variable in der getInstance-Methode definieren, nicht als Klassenmember. Das verhindert Probleme mit der Initialisierungs-reihenfolge der statischen Variablen.



  • wow, das ist schonmal hilfreich, momentan sieht mein singleton so aus:

    template<typename T>
    	class Singleton
    	{
    		static T* m_instance;
    
    	public:
    
    		Singleton()
    		{
    			if(m_instance != 0)
    				throw std::exception("Instance already exists!");
    			m_instance = (T*)this;
    		}
    
    		virtual ~Singleton()
    		{
    			if(m_instance != 0)
    				delete m_instance;
    			m_instance = 0;
    		}
    
    		static T* GetInstancePtr() { return m_instance; }
    		static T& GetInstance()
    		{
    			if(m_instance == 0)
    				throw std::exception("Instance not yet created!");
    			return *m_instance;
    		}
    	};
    

    d.h. ich soll die m:istance einfach in GetInstance schieben? bzw und auch in GetInstancePtr?

    Mfg, Xaser



  • google mal nach "meyers singleton".

    Was mir an deinem singleton nicht gefällt:
    - der Konstruktor ist public - wozu?
    - du hantierst mit einem Pointer auf T. Mit dem meyers-Singleton geht das einfacher. Die ganzen Abfragen auf 0 entfallen dann.



  • Ähm, habe jetzt nur kurz gegoogelt, da ich nur kurz am Rechner war, aber mir scheint als wäre der Meyer Singleton auch eingeschränkter, was die benutzung angeht. Momentan sieht meine Version des Meyer Singletons so aus:

    template<typename T>
    class Singleton {
    public:
    static Singleton& Instance() {
      static T m_instance;
      return m_instance;
    }
    
    private:
    Singleton();
    ~Singleton();
    };
    


  • XaserIII schrieb:

    Ähm, habe jetzt nur kurz gegoogelt, da ich nur kurz am Rechner war, aber mir scheint als wäre der Meyer Singleton auch eingeschränkter, was die benutzung angeht.

    Was meinst du mit "eingeschränkt"? Schließlich ist ja die Einschränkung Sinn & Zweck eines Singletons 🙂



  • damit meine ich, dass bsp weise man nicht einfach mehr einen pointer darauf bekommt oder sehe ich das jetzt komplett falsch?



  • XaserIII schrieb:

    damit meine ich, dass bsp weise man nicht einfach mehr einen pointer darauf bekommt oder sehe ich das jetzt komplett falsch?

    Singleton* ptr = &Singleton<..>::Instance();



  • Hallo XaserIII ,

    wofür brauchst du denn noch den Zeiger, wenn du eine Referenz erhältst?



  • Uh man, da hab ich jetzt aber wirklich gerade nicht nachgedacht, sorry. Aber wie kann man jetzt noch paramameter an den konstruktor der abegleiteten Klasse weitergeben?

    template<typename T>
    	class Singleton
    	{
    
    	protected:
    
    		Singleton() { }
    		~Singleton() { }
    
    	public:
    
    		static T& GetInstance()
    		{
    			static T m_instance;
    			return m_instance;
    		}
    	};
    


  • if(m_instance != 0)
                    delete m_instance;
    

    Das ist Blödsinn. Du kannst ein delete auf einen Nullzeiger ohne Probleme aufrufen, ja sogar folgendes ist erlaubt: http://ideone.com/rHSMo
    (Der C-Cast ist nur zu Demonstrationszwecken hier und natürlich hässlich.)


  • Mod

    314159265358979 schrieb:

    if(m_instance != 0)
                    delete m_instance;
    

    Das ist Blödsinn. Du kannst ein delete auf einen Nullzeiger ohne Probleme aufrufen, ja sogar folgendes ist erlaubt: http://ideone.com/rHSMo
    (Der C-Cast ist nur zu Demonstrationszwecken hier und natürlich hässlich.)

    Der Code ist Blödsinn, die Begründung allerdings auch.
    Ein Test auf 0 ist zwar regelmäßig nicht erforderlich, deshalb aber nicht unbedingt sinnlos. Schließlich werden Programme nicht bloß ausgeführt sondern auch gelesen.

    Hier hingegen ist der Test schlicht falsch:
    m_instance kann/darf nicht 0 sein, wäre es an dieser Stelle 0, läge ein Bug vor. Folglich gehört ein assert an diese Stelle.



  • XaserIII schrieb:

    Uh man, da hab ich jetzt aber wirklich gerade nicht nachgedacht, sorry. Aber wie kann man jetzt noch paramameter an den konstruktor der abegleiteten Klasse weitergeben?

    Ich würde eine Singleton-Klasse eher so entwerfen, daß sie ohne zusätzliche Parameter-Angaben erzeugt werden kann. Andernfalls bekommst du schnell Probleme mit der Initialisierungsreihenfolge.



  • Ja das war ja für mich gerade das schöne an meinem alten Singleton, dort konnte man quasi einfach new T(params) machen und die klasse war einmal initialisiert und konnte nicht nochmal erzeugt werden.

    Hingegen mein neuer "Meyers Singleton" verhindert nichtmal das man nur eine instanz davon erzeugen kann, da der konstruktor von T public sein muss, damit das ganze funktioniert. Jedenfalls sehe ich das momentan so.

    Wie sollte denn eine abstrakte Singleton Klasse aussehen, mit der man auch parameter an die abgeleiteten Klassen geben kann?

    MfG, Xaser



  • Von wo aus bekommst du denn die Parameter übergeben? Wenn das aus dem Nutzer-Code kommt, hast du ein Problem weil du nicht weißt, welcher getInstance()-Aufruf tatsächlich der erste ist - der dann dein Singleton-Objekt initialisiert.

    Und ich erinnere mich düster, daß Meyers auch wirksam verhindert hat daß du die Klasse manuell erzeugen kann.



  • peww

    Also das wäre natürlich fatal. da würde ich lieber bei meiner alten singleton klasse bleiben. Aber ich kann mir ehrlich gesagt nich vorstellen, dass man vom Meyers Singleton nicht eine version machen kann bei der man die abgeleitete Klasse mit Parametern initialisiert.

    MfG, Xaser


Log in to reply