Serialisierung einer "Datenbank" (DLL)



  • Folgende Ausgangslage: Ich habe verschiedene Klassen welche ich über ObjectManager zentral verwalten möchte. Die Klassen haben teilweise Pointer welche auf Instanzen anderer Klassen verweisen (siehe ObjectB::_PointerToObjectA). Voraussetzung ist dabei dass die Datenbank als DLL kompiliert werden kann (verschiedene Programme sollen die DLL nutzen können) :

    typedef int64_t Id;
    
    class DATABASE_DLL Object {
    
      Id _Id;
    
      public:
      Object();
      virtual ~Object();
    
      void setId(Id id);
      Id getId();
    
    };
    
    template<class T>
    class DATABASE_DLL ObjectManager : public Singleton<ObjectManager<T>> {
    
      std::list<T> _Data;
      Id _NextId;
    
      public:
      ObjectManager();
      ~ObjectManager();
    
      T* create();
      T* get(Id id);
      bool remove(Id id);
    
    };
    
    class DATABASE_DLL ObjectA : public Object;
    typedef ObjectManager<ObjectA> ObjectAManager;
    
    class ObjectB : public Object {
    
      ObjectA*  _PointerToObjectA;
    
      public:
      ObjectB();
      ~ObjectB();
    
    };
    typedef ObjectManager<ObjectB> ObjectBManager;
    
    void DATABASE_DLL ObjectB::serialize() {
       //..
       Id objectAId;
       read(&objectAId);
       _PointerToObjectA = ObjectAManager::getInstance().get(objectAId);
       //.. 
    }
    

    Nun habe ich bei der Serialisierung ein Problem: ObjectB braucht bei beim Laden Zugriff auf den ObjectAManager, was theoretisch über ObjectAManager::getInstance() möglich wäre. Nur laufe ich da in das Problem das für die DLL und die Anwendung eine eigene Instanz des Singletons angelegt wird.

    Die zweite Möglichkeit wäre es auf die Singletons zu verzichten, dann müssten ich entweder jeder ObjectB-Instanz einen Pointer zum ObjectAManager mitgeben, was auch nicht gerade schön ist oder der serialize()-Funktion den zugehörigen ObjectManager mitgeben (was heisst das ich das ganze Serializing selbst schreiben müsste).

    Die dritte Möglichkeit wäre dann noch die "Datenbank" nicht als DLL sondern fest in die Anwendung zu kompilieren, was bedeuten würde dass diese auch für jede Anwendung gepflegt werden müsste.

    Irgendwie ist alles unschön. Kann mir jemand helfen wie sich das am einfachsten umsetzen lässt?



  • für die DLL und die Anwendung eine eigene Instanz des Singletons angelegt wird.

    Erklär mal



  • manni66 schrieb:

    für die DLL und die Anwendung eine eigene Instanz des Singletons angelegt wird.

    Erklär mal

    Da ich sowohl in der Anwendung als auch in der DLL verwende werden faktisch 2 Singleton-Instanzen angelegt (pro Compilation-Unit eine Instanz). Das wirkt sich damit aus dass beim Laden die Zuweisung des ObjektA-Pointers nicht funktioniert da der ObjectManager in der DLL-Instanz keine Objekte enthält, diese sind ja in der Instanz der Anwendung.

    Zumindest ist das die Erklärung welche ich mir zurechtgelegt habe, kann also gut sein dass ich falsch liege 😉

    Ich habe noch eine weitere Möglichkeit: Anstatt der Pointer speichere ich einfach die ID's der verbundenen Objekte, was aber dann später zu einem ungemein höheren Aufwand für die CPU führt da ich ja immer zuerst die Objekte anhand der ID abfragen muss. Aber das Problem der Serialisierung wäre dann zumindest ziemlich elegant gelöst.



  • Rookie86 schrieb:

    Da ich sowohl in der Anwendung als auch in der DLL verwende werden faktisch 2 Singleton-Instanzen angelegt (pro Compilation-Unit eine Instanz). Das wirkt sich damit aus dass beim Laden die Zuweisung des ObjektA-Pointers nicht funktioniert da der ObjectManager in der DLL-Instanz keine Objekte enthält, diese sind ja in der Instanz der Anwendung.

    Was ist eine Compilation-Unit?
    Heißt es Singleton, weil mehrere angelegt werden?



  • manni66 schrieb:

    Rookie86 schrieb:

    Da ich sowohl in der Anwendung als auch in der DLL verwende werden faktisch 2 Singleton-Instanzen angelegt (pro Compilation-Unit eine Instanz). Das wirkt sich damit aus dass beim Laden die Zuweisung des ObjektA-Pointers nicht funktioniert da der ObjectManager in der DLL-Instanz keine Objekte enthält, diese sind ja in der Instanz der Anwendung.

    Was ist eine Compilation-Unit?
    Heißt es Singleton, weil mehrere angelegt werden?

    Einfach gesagt sind die DLL und die Applikation zwei verschieden Compilation-Units was dazu führt das die DLL und die Applikation sich nicht ein Singleton teilen sondern jeweils selbst eine Instanz anlegen. Nutzt man also ObjectManager<T>::getInstance() sowohl in der DLL als auch in der Applikation bekommt man zwei verschiedene Pointer zurück.

    Ich habe aber eine Lösung gefunden:

    Das Template darf nicht nur in der Header-Datei der DLL definiert sein sondern die Funktionen müssen in die CPP-Datei. Ausserdem muss man jene ObjectManager welche man in der DLL benötigt per "template class" definieren.

    ObjectManager.hpp

    template<class T>
     class DATABASE_DLL ObjectManager { 
    
        //...
    
        ObjectManager();
        ~ObjectManager();
    
        static ObjectManager<T>& getInstance();
    
        T* create(T object);
    
        T* get(Id id);
    
        // ...
     };
    

    ObjectManager.cpp

    template<class T>
        ObjectManager<T>::ObjectManager() {
          //...
        }
    
        template<class T>
        ObjectManager<T>::~ObjectManager() {
    
        }
    
        template<class T>
        ObjectManager<T>& ObjectManager<T>::getInstance() {
          static ObjectManager<T> instance;
          return instance;
        }
    
        template<class T>
        T* ObjectManager<T>::create(T object) {
          //...
        }
    
        //Nun kann man die benötigten Templates fest in der DLL erstellen
        template class ObjectManager<ObjectA>;
        template class ObjectManager<ObjectB>;
    

    Greift man jetzt auf ObjectManager<T>::getInstance() zu bekommt man sowohl in der DLL als auch in der Anwendung denselben Pointer zurück.


Log in to reply