Design von Resourcen



  • Ich bin schon oefter ueber dieses Problem gestolpert:

    class Resource
    {
    public:
      Resource() {}
      virtual ~Resource()
      {
        Unload(); // aufraeumen
      }
    
      virtual void Load() const {};
      virtual void Unload() const {};
    };
    
    class Sprite : public Resource
    {
      mutable /* sprite data */
    public:
      void Load() const { }
      void Unload() const { }
      /* ... */
    };
    
    delete new Sprite();
    

    ..und schon gibts ein Memoryleak. (Sprite-Destruktor wird vor ~Resource() ausgefuehrt, und ~Resource() ruft nur Resource::Unload() auf.)

    Gibt es dafuer vielleicht ein passendes Designpattern? Ist zwar kein Beinbruch, aber mich stoert es schon, jedesmal explizit in ~Sprite Unload() aufrufen zu muessen.

    Edit: Es ist Abscht, dass die Resource nicht gleich im Konstruktor geladen und im Destruktor entladen wird (Resource aquisition is initialization hiess das, oder?). Es soll schon wie ein Cache funktionieren.

    -Gunnar



  • Und um meinen Monolog weiterzufuehren:

    Ich ersetze meine Spritedaten durch ein

    class Sprite : public Resource
    {
      /*...*/
      mutable auto_ptr<SpriteData> sprite_data
      /*...*/
      void Load()
      {
        auto_ptr.reset(new SpriteData());
      }
    
      void Unload()
      {
        auto_ptr.reset(0);
      }
    };
    

    Und lasse den Unload-Aufruf in ~Resource weg.

    Danke fuers zuhoeren.
    -Gunnar



  • Was aber auf das gleiche hinausgeht als hätte man in Resource den Destruktor virtuell gemacht und Unload für Sprite in ~Sprite aufgerufen ?!



  • Warum erbt Sprite von Resource?
    Ich verstehe den Sinn nicht.



  • @Shade:
    Ok, Sprite heisst bei mir im Programm auch SpriteResource. Dort koennen mehrere Sprite-Instanzen auf die selbe SpriteResource zugreifen. Dazu gibts ein ResourceManager, der Resources verwaltet, und bei Bedarf laedt oder entlaedt.

    @Knuddlbaer:
    Gerade das wollte ich ja nicht.



  • Gunnar schrieb:

    @Shade:
    Ok, Sprite heisst bei mir im Programm auch SpriteResource. Dort koennen mehrere Sprite-Instanzen auf die selbe SpriteResource zugreifen. Dazu gibts ein ResourceManager, der Resources verwaltet, und bei Bedarf laedt oder entlaedt.

    Und wozu muss Resource dann eine konkrete Klasse sein? Das klingt fuer mich eher wie ein Interface...



  • Nach meinem 2. Post ist Resource doch zu einem Interface geworden.



  • Gunnar schrieb:

    Nach meinem 2. Post ist Resource doch zu einem Interface geworden.

    Nur das ich 0 Ahnung habe was es darstellen soll?

    Der 'Wrapper' Sprite macht nix anderes als einen auto_ptr auf ein SpriteData Objekt zu haben... Warum dann nicht gleich nen auto_ptr?

    Ich verstehe das ganze Problem nicht.

    Es gibt nen ResourceManager, der nach beliebem resourcen ladet und freigibt.

    Also mach in in Interface:

    struct Resource
    {
      virtual void Load()=0;
      virtual void Unload()=0;
    };
    

    Dann mache ich konkrete Resourcen Klassen:

    class Sprite : public Resource
    {
    private:
      //some data;
    public:
      Sprite() { Load(); }
      ~Sprite() { Unload(); }
      void Load() { /*...*/ }
      void Unload() { /*...*/ }
    };
    

    uU noch ein state rein ob die resource gerade geladen ist oder nicht.



  • Hmm. Ich sollte mir nicht soviel Gedanken drum machen, und es simpel halten. Ausserdem ist es schon ziemlich spaet.
    -Gunnar

    Posting vor Edit:

    Danke, aber damit waeren wir wieder am Anfang. Mein anfaengliches nicht-Problem war ja, in ~SpriteResource Unload() aufrufen zu muessen. Ich hatte irgendwie das Gefuehl, das SpriteResource sich durch den Unload()-Aufruf in ~SpriteResource in die Semantik der Resource-Klasse einmischt. Dass sich eine Resource einfach selbst entlaedt ist in Resource selbst nicht festgelegt. Das Resource-Interface sagt nur aus, man kann sie laden und wieder entladen, aber man erwartet nicht dass das zufaellig passiert.

    In diesem konkreten Fall ist es natuerlich aus sehr sehr vielen Gruenden egal, zumal der ResourceManager sowieso keine Sprites loescht, die nicht vorher ein Unload() verpasst bekommen haben und ueberhaupt.

    -Gunnar



  • Gunnar schrieb:

    Ich hatte irgendwie das Gefuehl, das SpriteResource sich durch den Unload()-Aufruf in ~SpriteResource in die Semantik der Resource-Klasse einmischt.

    Es gibt keine resource-Klasse. Es gibt nur ein Interface resource.
    SpriteResource IST die Resource.

    uU suchst du eher etwas wie einen ScopeGuard?



  • Ok, das ueberzeugt mich. Hab nun ein reines Gewissen 🙂

    Werden fuer ein reines Interface eigentlich Standardkonstruktoren/destruktoren erstellt?



  • Gunnar_ schrieb:

    Werden fuer ein reines Interface eigentlich Standardkonstruktoren/destruktoren erstellt?

    Es wird immer ein Standard Konstruktor erstellst, wenn du selber keinen Konstruktor definierst.

    Wenn du ds Interface abstrakt machen willst:

    struct Interface
    {
      virtual ~Interface() = 0;
      virtual void Load() = 0;
      virtual void Unload() = 0;
    };
    
    Interface::~Interface() {}
    

Anmelden zum Antworten