У меня есть сценарий, когда многим объектам может понадобиться загрузить какой-либо ресурс, но когда путь к ресурсу одинаков, объект ресурса должен быть общим. Следующий упрощенный код представляет вышеуказанную концепцию:
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;
};