Problem bei Verwendung von share_ptr oder unique_ptr



  • Guten Abend zusammen,

    ich baue gerade einen Texturen Manager um habe extra eine Klasse Texture. Diese Soll die Texture beinhalten und gegebenfalls auch zeichnen.

    Nun habe ich im Texture Manager eine std::map die mir die Texture Objekte festhalten soll.

    Zuerst dachte ich, dass wenn ich unique_ptr benutze, ich den Vorteil habe, dass ich nicht jede Texture Instanz löschen muss, wenn ich den std::map bereinigen will.

    Das Problem bei unique_ptr ist halt das ich beschränkten Zugriff darauf habe. Hab mich dann also für shared_ptr entschieden. Da ich zwischendurch auf die Texture Instanzen zugreifen möchte.

    Nun ist es bei shared_ptr wohl so, dass sie eine eigene Ressource haben und eine 2. besitzen können. Was mich ein wenig verwirrt.

    Ich möchte einfach nur eine std::map haben bei der ich auf die Instanzen auch zugreifen kann. Soweit ich weiß könnte ich den shared_ptr einer temporären Variable zuordnen, aber das ist mir auch irgendwie zu doof.

    Hier mal etwas Code.

    class TextureManager
        {
        public:
            static TextureManager *instance();
            static void delInstance();
    
            /*
             * load Texture
             * -----------------------------------
             * Creates a Texture Object with the Texture and puts it in m_loadedTextures as unqiue_ptr
             */
            void loadTexture(Game *game, const std::string filename);
    
            /*
             * Destroy Map m_loadedTextures
             * -----------------------------------
             * Destroys all Texture Objects in the map and clear it completly
             */
            void destroyLoadedTextures();
    
        private:
            TextureManager();
            TextureManager(const TextureManager &);
            ~TextureManager();
    
            static TextureManager *m_Instance;
    
            /*
             * Textures
             * ----------------------------
             * all Textures that are loaded are here
             */
            std::map<std::string, std::shared_ptr<Texture>> m_loadedTextures;
    
        };
    
    Ghuul::TextureManager *Ghuul::TextureManager::m_Instance = nullptr;
    
    Ghuul::TextureManager *Ghuul::TextureManager::instance()
    {
        if (m_Instance == nullptr)
            m_Instance = new TextureManager();
        return m_Instance;
    }
    
    void Ghuul::TextureManager::delInstance()
    {
        if (m_Instance != nullptr)
            delete m_Instance;
        m_Instance = nullptr;
    }
    
    void Ghuul::TextureManager::loadTexture(Game *game, const std::string filename)
    {
        std::shared_ptr<Texture> texture(new Texture());
        texture->load(game, filename);
        m_loadedTextures.insert(std::pair<std::string, std::shared_ptr<Texture>>(filename, texture));
    }
    
    void Ghuul::TextureManager::destroyLoadedTextures()
    {
        m_loadedTextures.erase(m_loadedTextures.begin(), m_loadedTextures.end());
    }
    

    Kompiliert wird das ohne Probleme. Nur muss ich wohl momentan, wenn ich auf eine Texture Instanz zugreifen will, das hier machen (nicht getestet)

    std::shared_ptr<Texture> texture = m_loadedTextures.at("Image");
        texture->draw();
    

    Wir dort der Speicher wirklich geteilt? Wenn ich jetzt draw aufrufe, gilt das wirklich für das Objekt im std::map?



  • Naja, jein, würde ich sagen:
    Das Objekt in der map ist ja nicht Deine Textur, sondern ein Pointer darauf. Nach der Zuweisung

    std::shared_ptr<Texture> texture = m_loadedTextures.at("Image");
    

    hast Du einen zweiten Pointer auf die entsprechende Textur.
    Aber brauchst Du den wirklich? Du kannst doch einfach

    m_loadedTextures.at("Image")->draw();
    

    rufen?!
    Das geht dann übrigens auch, wenn die map unique_ptr beherbergt.



  • Belli schrieb:

    Naja, jein, würde ich sagen:
    Das Objekt in der map ist ja nicht Deine Textur, sondern ein Pointer darauf. Nach der Zuweisung

    std::shared_ptr<Texture> texture = m_loadedTextures.at("Image");
    

    hast Du einen zweiten Pointer auf die entsprechende Textur.
    Aber brauchst Du den wirklich? Du kannst doch einfach

    m_loadedTextures.at("Image")->draw();
    

    rufen?!
    Das geht dann übrigens auch, wenn die map unique_ptr beherbergt.

    ah cool. stimmt. hatte das wohl mal probiert, aber da muss ich was falsch gemacht haben. hatte daher zuerst den Sinn von unique_ptr nicht verstanden. Aber jetzt geht es. shared_ptr brauche ich nur dann wenn ich 2 oder mehr Pointer drauf zeigen lassen will?



  • Ich würde sagen, shared_ptr brauchst Du, wenn der Besitz, also die Verantwortung für das Löschen des Objektes hinter dem Zeiger, nicht eindeutig geklärt werden kann - ich denke, einigermaßen selten.

    PS: Ich bin aber nicht so der Theorie-Papst, das können einige andere hier sicherlich besser auf den Punkt bringen



  • Bennisen schrieb:

    Das Problem bei unique_ptr ist halt das ich beschränkten Zugriff darauf habe. Hab mich dann also für shared_ptr entschieden. Da ich zwischendurch auf die Texture Instanzen zugreifen möchte.

    da hast du irgendwas grundlegend falsch verstanden. Der Zugriff auf das enthaltene Objekt ist bei beiden Varianten gleich. Unterschiede gibt es lediglich beim Kopier- und Zuweisungsverhalten.


Anmelden zum Antworten