Skip to main content
deleted 11 characters in body
Source Link
Mutoh
  • 817
  • 7
  • 18
    struct TextureFactory {
        
        std::shared_ptr<Texture> texturePtr;
        
        /* ... */
        
        std::shared_ptr<ResourceBase> load() {
            if (!texturePtr) {
                texturePtr = std::make_shared<Texture>();
                texturePtr->loadFromFile(/* ... */);
            }
            
            return texturePtr;
        }
        
    };

    /* ... */

    struct ResourceManager {
        
        template <class T>
        std::shared_ptr<T> load(std::string key) {
            auto& factoryFunctor = m_factories.at(key);
            std::shared_ptr<ResourceBase> ptr = factoryFunctor();
            
            auto castRawPtr = dynamic_cast<ResourceBase*>dynamic_cast<T*>(ptr.get());
            assert(castRawPtr);
            
            return std::shared_ptr<T>(ptr, castRawPtr);
        }
        
    };
    struct TextureFactory {
        
        std::shared_ptr<Texture> texturePtr;
        
        /* ... */
        
        std::shared_ptr<ResourceBase> load() {
            if (!texturePtr) {
                texturePtr = std::make_shared<Texture>();
                texturePtr->loadFromFile(/* ... */);
            }
            
            return texturePtr;
        }
        
    };

    /* ... */

    struct ResourceManager {
        
        template <class T>
        std::shared_ptr<T> load(std::string key) {
            auto& factoryFunctor = m_factories.at(key);
            std::shared_ptr<ResourceBase> ptr = factoryFunctor();
            
            auto castRawPtr = dynamic_cast<ResourceBase*>(ptr.get());
            assert(castRawPtr);
            
            return std::shared_ptr<T>(ptr, castRawPtr);
        }
        
    };
    struct TextureFactory {
        
        std::shared_ptr<Texture> texturePtr;
        
        /* ... */
        
        std::shared_ptr<ResourceBase> load() {
            if (!texturePtr) {
                texturePtr = std::make_shared<Texture>();
                texturePtr->loadFromFile(/* ... */);
            }
            
            return texturePtr;
        }
        
    };

    /* ... */

    struct ResourceManager {
        
        template <class T>
        std::shared_ptr<T> load(std::string key) {
            auto& factoryFunctor = m_factories.at(key);
            std::shared_ptr<ResourceBase> ptr = factoryFunctor();
            
            auto castRawPtr = dynamic_cast<T*>(ptr.get());
            assert(castRawPtr);
            
            return std::shared_ptr<T>(ptr, castRawPtr);
        }
        
    };
deleted 1223 characters in body
Source Link
Mutoh
  • 817
  • 7
  • 18

Edit: The example below makes a dangerous use of shared_ptr, please refer tosee the edit belowat the bottom.

Edit: I have found that the use ofit is dangerous to transfer a raw pointer that's already owned by a shared_ptr in my example is erroneous and can lead to multiple deletions ofanother shared_ptr. The second shared_ptr will have a different reference counting from the resourcefirst and it is 100% certain that the object will be destroyed at least twice. Please refer

Instead of returning void* or BaseClass*, prefer to return shared_ptr<void> or shared_ptr<BaseClass> and remember to use the aliasing constructor of shared_ptr before returning shared_ptr<T> in your equivalent of the followingResourceManager::load<T> method from the example which, while also untested, doesn't showcase a dangerous practice:.

Something like:

    struct ResourceManagerTextureFactory {
        
        typedef std::function<std::shared_ptr<void> ()> TFactoryFunctor;
        
        std::map<std::string, TFactoryFunctor> m_factories;
        
        void subscribe (std::string key, TFactoryFunctor factory)shared_ptr<Texture> {texturePtr;
            m_factories[key] = factory;
        }
      /* ... */
        template <class T>
        std::shared_ptr<T>shared_ptr<ResourceBase> load (std::string key) {
            auto& factoryFunctor =if m_factories.at(key!texturePtr);
     {
       
          texturePtr = std::shared_ptr<void> ptr = factoryFunctormake_shared<Texture>();
            
            // Here we use the "aliasing" constructor of shared_ptr, which will allow us to use the same reference counting of
            /texturePtr->loadFromFile(/ the shared_ptr within the* factory.
            // 
            // Back in the previous example, this returned shared_ptr would have had a different referece counting from the
            // shared_ptr within the factory and this would have lead to the pointed resource getting destroyed at least twice
            // once all shared_ptr's stopped point to it.
            return std::shared_ptr<T>(ptr, static_cast<T*>(ptr.get()) */);
        }
        
    };

    struct ResourceFactory {
        
        std::string m_path;
        
        void setFilePath (std::string path) {
            m_path = path;
        }
        
        std::string getFilePath() const {
            return m_path;texturePtr;
        }
        
        virtual void* load() =0;
        
        void* operator() () {
            return this->load()};
        }
        
  /* ... };*/

    struct TextureFactory : ResourceFactoryResourceManager {
        
        // Now, only one shared_ptr is enough. We don't need to keep a rawtemplate pointer<class around.T>
        std::shared_ptr<Texture> m_texPtr;
        
        TextureFactoryshared_ptr<T> load(std::string fileNamekey) {
            setFilePath(TEXTURES_FOLDER + fileName);
        }
        
        std::shared_ptr<void> load() override {
          auto& factoryFunctor if= m_factories.at(!m_texPtrkey) {;
                m_texPtr = std::make_shared<Texture>();
             shared_ptr<ResourceBase> ptr = m_texPtr->loadFromFile(getFilePathfactoryFunctor());
            }
            
            // A shared_ptr<void> is essentially a void*, we're not changing much here.
            return m_texPtr;
        }
        
    };

    // ---

    ResourceManager daMan;

  auto castRawPtr void= subscribeTexturesdynamic_cast<ResourceBase*>() {
        daManptr.subscribe("hero", TextureFactoryget("hero.png"));
        daMan.subscribe("foe", TextureFactory("foe.png"));
        daMan.subscribe("tileset", TextureFactoryassert("tileset.png")castRawPtr);
    }

    void loadHeroTexture (Hero& hero) {
        auto texPtr = daMan.load<Texture>("hero");
        
       return hero.claimOwnershipstd::shared_ptr<T>(texPtrptr, castRawPtr); // Maybe you want 
 to keep track of who's using the resource?}
        hero.sprite.setTexture(*texPtr);
    };

Edit: The example below makes a dangerous use of shared_ptr, please refer to the edit below.

Edit: I have found that the use of shared_ptr in my example is erroneous and can lead to multiple deletions of the resource. Please refer to the following example which, while also untested, doesn't showcase a dangerous practice:

    struct ResourceManager {
        
        typedef std::function<std::shared_ptr<void> ()> TFactoryFunctor;
        
        std::map<std::string, TFactoryFunctor> m_factories;
        
        void subscribe (std::string key, TFactoryFunctor factory) {
            m_factories[key] = factory;
        }
        
        template <class T>
        std::shared_ptr<T> load (std::string key) {
            auto& factoryFunctor = m_factories.at(key);
            
            std::shared_ptr<void> ptr = factoryFunctor();
            
            // Here we use the "aliasing" constructor of shared_ptr, which will allow us to use the same reference counting of
            // the shared_ptr within the factory.
            // 
            // Back in the previous example, this returned shared_ptr would have had a different referece counting from the
            // shared_ptr within the factory and this would have lead to the pointed resource getting destroyed at least twice
            // once all shared_ptr's stopped point to it.
            return std::shared_ptr<T>(ptr, static_cast<T*>(ptr.get()));
        }
        
    };

    struct ResourceFactory {
        
        std::string m_path;
        
        void setFilePath (std::string path) {
            m_path = path;
        }
        
        std::string getFilePath() const {
            return m_path;
        }
        
        virtual void* load() =0;
        
        void* operator() () {
            return this->load();
        }
        
    };

    struct TextureFactory : ResourceFactory {
        
        // Now, only one shared_ptr is enough. We don't need to keep a raw pointer around.
        std::shared_ptr<Texture> m_texPtr;
        
        TextureFactory (std::string fileName) {
            setFilePath(TEXTURES_FOLDER + fileName);
        }
        
        std::shared_ptr<void> load() override {
            if (!m_texPtr) {
                m_texPtr = std::make_shared<Texture>();
                m_texPtr->loadFromFile(getFilePath());
            }
            
            // A shared_ptr<void> is essentially a void*, we're not changing much here.
            return m_texPtr;
        }
        
    };

    // ---

    ResourceManager daMan;

    void subscribeTextures() {
        daMan.subscribe("hero", TextureFactory("hero.png"));
        daMan.subscribe("foe", TextureFactory("foe.png"));
        daMan.subscribe("tileset", TextureFactory("tileset.png"));
    }

    void loadHeroTexture (Hero& hero) {
        auto texPtr = daMan.load<Texture>("hero");
        
        hero.claimOwnership(texPtr); // Maybe you want to keep track of who's using the resource?
        hero.sprite.setTexture(*texPtr);
    }

Edit: The example below makes a dangerous use of shared_ptr, please see the edit at the bottom.

Edit: I have found that it is dangerous to transfer a raw pointer that's already owned by a shared_ptr to another shared_ptr. The second shared_ptr will have a different reference counting from the first and it is 100% certain that the object will be destroyed at least twice.

Instead of returning void* or BaseClass*, prefer to return shared_ptr<void> or shared_ptr<BaseClass> and remember to use the aliasing constructor of shared_ptr before returning shared_ptr<T> in your equivalent of the ResourceManager::load<T> method from the example.

Something like:

    struct TextureFactory {
        
        std::shared_ptr<Texture> texturePtr;
        
        /* ... */
        
        std::shared_ptr<ResourceBase> load() {
            if (!texturePtr) {
                texturePtr = std::make_shared<Texture>();
                texturePtr->loadFromFile(/* ... */);
            }
            
            return texturePtr;
        }
        
    };

    /* ... */

    struct ResourceManager {
        
        template <class T>
        std::shared_ptr<T> load(std::string key) {
            auto& factoryFunctor = m_factories.at(key);
            std::shared_ptr<ResourceBase> ptr = factoryFunctor();
            
            auto castRawPtr = dynamic_cast<ResourceBase*>(ptr.get());
            assert(castRawPtr);
            
            return std::shared_ptr<T>(ptr, castRawPtr); 
        }
        
    };
Corrected example source
Source Link
Mutoh
  • 817
  • 7
  • 18

Edit: The example below makes a dangerous use of shared_ptr, please refer to the edit below.

Edit: I have found that the use of shared_ptr in my example is erroneous and can lead to multiple deletions of the resource. Please refer to the following example which, while also untested, doesn't showcase a dangerous practice:

    struct ResourceManager {
        
        typedef std::function<std::shared_ptr<void> ()> TFactoryFunctor;
        
        std::map<std::string, TFactoryFunctor> m_factories;
        
        void subscribe (std::string key, TFactoryFunctor factory) {
            m_factories[key] = factory;
        }
        
        template <class T>
        std::shared_ptr<T> load (std::string key) {
            auto& factoryFunctor = m_factories.at(key);
            
            std::shared_ptr<void> ptr = factoryFunctor();
            
            // Here we use the "aliasing" constructor of shared_ptr, which will allow us to use the same reference counting of
            // the shared_ptr within the factory.
            // 
            // Back in the previous example, this returned shared_ptr would have had a different referece counting from the
            // shared_ptr within the factory and this would have lead to the pointed resource getting destroyed at least twice
            // once all shared_ptr's stopped point to it.
            return std::shared_ptr<T>(ptr, static_cast<T*>(ptr.get()));
        }
        
    };

    struct ResourceFactory {
        
        std::string m_path;
        
        void setFilePath (std::string path) {
            m_path = path;
        }
        
        std::string getFilePath() const {
            return m_path;
        }
        
        virtual void* load() =0;
        
        void* operator() () {
            return this->load();
        }
        
    };

    struct TextureFactory : ResourceFactory {
        
        // Now, only one shared_ptr is enough. We don't need to keep a raw pointer around.
        std::shared_ptr<Texture> m_texPtr;
        
        TextureFactory (std::string fileName) {
            setFilePath(TEXTURES_FOLDER + fileName);
        }
        
        std::shared_ptr<void> load() override {
            if (!m_texPtr) {
                m_texPtr = std::make_shared<Texture>();
                m_texPtr->loadFromFile(getFilePath());
            }
            
            // A shared_ptr<void> is essentially a void*, we're not changing much here.
            return m_texPtr;
        }
        
    };

    // ---

    ResourceManager daMan;

    void subscribeTextures() {
        daMan.subscribe("hero", TextureFactory("hero.png"));
        daMan.subscribe("foe", TextureFactory("foe.png"));
        daMan.subscribe("tileset", TextureFactory("tileset.png"));
    }

    void loadHeroTexture (Hero& hero) {
        auto texPtr = daMan.load<Texture>("hero");
        
        hero.claimOwnership(texPtr); // Maybe you want to keep track of who's using the resource?
        hero.sprite.setTexture(*texPtr);
    }

Edit: The example below makes a dangerous use of shared_ptr, please refer to the edit below.

Edit: I have found that the use of shared_ptr in my example is erroneous and can lead to multiple deletions of the resource. Please refer to the following example which, while also untested, doesn't showcase a dangerous practice:

    struct ResourceManager {
        
        typedef std::function<std::shared_ptr<void> ()> TFactoryFunctor;
        
        std::map<std::string, TFactoryFunctor> m_factories;
        
        void subscribe (std::string key, TFactoryFunctor factory) {
            m_factories[key] = factory;
        }
        
        template <class T>
        std::shared_ptr<T> load (std::string key) {
            auto& factoryFunctor = m_factories.at(key);
            
            std::shared_ptr<void> ptr = factoryFunctor();
            
            // Here we use the "aliasing" constructor of shared_ptr, which will allow us to use the same reference counting of
            // the shared_ptr within the factory.
            // 
            // Back in the previous example, this returned shared_ptr would have had a different referece counting from the
            // shared_ptr within the factory and this would have lead to the pointed resource getting destroyed at least twice
            // once all shared_ptr's stopped point to it.
            return std::shared_ptr<T>(ptr, static_cast<T*>(ptr.get()));
        }
        
    };

    struct ResourceFactory {
        
        std::string m_path;
        
        void setFilePath (std::string path) {
            m_path = path;
        }
        
        std::string getFilePath() const {
            return m_path;
        }
        
        virtual void* load() =0;
        
        void* operator() () {
            return this->load();
        }
        
    };

    struct TextureFactory : ResourceFactory {
        
        // Now, only one shared_ptr is enough. We don't need to keep a raw pointer around.
        std::shared_ptr<Texture> m_texPtr;
        
        TextureFactory (std::string fileName) {
            setFilePath(TEXTURES_FOLDER + fileName);
        }
        
        std::shared_ptr<void> load() override {
            if (!m_texPtr) {
                m_texPtr = std::make_shared<Texture>();
                m_texPtr->loadFromFile(getFilePath());
            }
            
            // A shared_ptr<void> is essentially a void*, we're not changing much here.
            return m_texPtr;
        }
        
    };

    // ---

    ResourceManager daMan;

    void subscribeTextures() {
        daMan.subscribe("hero", TextureFactory("hero.png"));
        daMan.subscribe("foe", TextureFactory("foe.png"));
        daMan.subscribe("tileset", TextureFactory("tileset.png"));
    }

    void loadHeroTexture (Hero& hero) {
        auto texPtr = daMan.load<Texture>("hero");
        
        hero.claimOwnership(texPtr); // Maybe you want to keep track of who's using the resource?
        hero.sprite.setTexture(*texPtr);
    }
deleted 8 characters in body
Source Link
Mutoh
  • 817
  • 7
  • 18
Loading
deleted 8 characters in body
Source Link
Mutoh
  • 817
  • 7
  • 18
Loading
deleted 25 characters in body
Source Link
Mutoh
  • 817
  • 7
  • 18
Loading
Source Link
Mutoh
  • 817
  • 7
  • 18
Loading