фабрика общих объектов - обновление карты слабых_птр - PullRequest
0 голосов
/ 26 октября 2019

У меня есть сценарий, когда многим объектам может понадобиться загрузить какой-либо ресурс, но когда путь к ресурсу одинаков, объект ресурса должен быть общим. Следующий упрощенный код представляет вышеуказанную концепцию:

struct Obj
{
};

struct SharedObjects
{
    std::shared_ptr<Obj> CreateObj(const std::string& key)
    {
        auto itr = registry_.find(key);
        if(itr != registry_.end())
        {
            return itr->second.lock();
        }
        auto obj = std::make_shared<Obj>();
        registry_[key] = obj;
        return obj;
    }

    void ObjRemoved(const std::string& key)
    {
        auto itr = registry_.find(key);
        if(itr != registry_.end())
        {
            if(!itr->second.use_count())
            {
                registry_.erase(itr);
            }
        }
    }
private:
    std::unordered_map<std::string, std::weak_ptr<Obj>> registry_;
};

int main()
{
    SharedObjects sharedObjects;
    auto p1 = sharedObjects.CreateObj("a");
    auto p2 = sharedObjects.CreateObj("b");
    auto p3 = sharedObjects.CreateObj("a");

    p2.reset();
    sharedObjects.ObjRemoved("b");
}

Интересно, как я могу улучшить обновление карты слабых_птров? Как видите, я вызываю функции reset и ObjRemoved. У тебя есть идеи ? (Может быть, я должен использовать какой-то шаблон дизайна). Видите ли вы какие-либо другие места в коде, которые можно улучшить?

Edit1 Вот возможное решение:

можно удалить пустую слабую_птр из объекта Obj:

struct Obj
{
    Obj::Obj(std::function<void()> clb): clb_(std::move(clb))
    {}
    Obj::~Obj()
    {
        clb_();
    }

private:
    std::function<void()> clb_;
};

Модифицированная функция CreateObj (удалена функция ObjRemoved):

std::shared_ptr<Obj> SharedObjects::CreateObj(const std::string& key)
{
    auto itr = registry_.find(key);

    if(itr != registry_.end())
    {
        return itr->second.lock();
    }

   auto obj = std::make_shared<Obj>([this, key]
   {
       registry_.erase(key);
   });

   registry_[key] = obj;
   return obj;
}

Edit2 Альтернативное решение без интеллектуальных указателей:

struct Obj
{
};

struct SharedObj
{
    Obj* CreateObj(const std::string& key)
    {
        auto itr = registry.find(key);
        if(itr != registry.end())
        {
            ++(itr->second.refCount);
            return &itr->second.obj;
        }

        auto& objRecord = registry[key] = ObjRecord{};
        return &objRecord.obj;
    }

    void RemoveObj(const std::string& key)
    {
        auto itr = registry.find(key);
        if (itr != registry.end())
        {
            auto& refCount = itr->second.refCount;
            --refCount;

            if (refCount == 0)
            {
                registry.erase(itr);
            }
        }
    }
private:
    struct ObjRecord
    {
        Obj obj;
        std::uint16_t refCount{1};
    };
    std::unordered_map<std::string, ObjRecord> registry;
};
...