我实现了一个简单的资源管理器 - 一切都很好,直到我尝试实现其析构函数以进行(紧急)清理(例如在致命异常的情况下)。我找不到一种方法来做到这一点:
template<typename T>
class ResourceManager
{
public:
std::unordered_map<std::string, std::weak_ptr<T> > resource_map;
std::shared_ptr<T> getResource(std::string name)
{
std::shared_ptr<T> res = resource_map[name].lock();
if(!res)
{
res = std::shared_ptr<T>(new T(this, name));
resource_map[name] = res;
}
return std::move(res);
}
void Release(std::string name)
{
resource_map.erase(name);
};
~ResourceManager(void) { /* ???? */}
};
class Texture
{
private:
ResourceManager<Texture> * manager_;
std::string name_;
public:
Texture(ResourceManager<Texture> * manager, std::string& name)
: manager_(manager), name_(name) { }
~Texture(void){
manager_->Release(name_);
}
};
显然,我必须遍历所有活动资源...但是,如果资源管理器在技术上不是资源的(唯一)所有者,我该如何释放它们?这可能是设计缺陷,如果是这种情况,请提出替代方案。
编辑:为了响应答案,定义"资源管理器",我想权威缓存 - 存储对资源的引用,可以查找资源(=没有重复)并在内存中管理它们的状态(内存中,仅描述(=路径+类型)和释放),所有这些都尽可能自动化。(应该有单独的资源加载器,但对于这个问题来说并没有太大变化)
所以,你的代码并没有做很多事情来阐明你的整体设计,在这里,但是......
实现时,资源管理器似乎只有指向资源的弱指针。这表明它不对实际资源本身的生存期负责,因此不应在其析构函数中清理这些资源。
如果希望资源管理器成为资源数据的权威所有者,则需要更改其设计/实现。例如,您可以让它将shared_ptr
存储到资源本身,并且只将weak_ptr
传递给客户端。或者只是存储unique_ptr
并传递指向客户端代码的裸指针。
但正如所写,您不需要(也真的不能)做任何事情来清理~ResourceManager()
中的资源。
为了提出替代方案,我们需要知道您的资源管理器应该具有什么目的。
- 您是否希望它充当"资源集合",即在明确释放资源之前保持资源活动状态?
- 或者您希望它成为一个"资源缓存",保持资源处于活动状态,直到它决定应该释放一些资源以释放内存?
- 或者你真的希望它不让任何资源保持活动状态,而只是保留一个可能被其他东西保持活动状态的资源列表?
请记住,C++中的shared_ptr
不像 GC 那样工作。 即,如果您销毁/重置对某个对象的最后一个shared_ptr
,即使该对象有weak_ptr
,该对象也会立即被删除。
因此,方法(1)和(2)可能很有意义。(3)然而,这就是你目前拥有的,只是很少有意义(如果有的话)。