【问题标题】:How to controll shared ptr reference count?如何控制 shared_ptr 引用计数?
【发布时间】:2019-12-06 13:28:26
【问题描述】:

我正在为我的游戏引擎创建一个资源管理器。基本上它有一个 unordered_map 存储资源的路径作为键和值存储加载的资源。

这是负责加载资源的代码。

std::shared_ptr<T> LoadAsset(const String& _path)
{
    if (auto asset = m_assets.find(_path); asset != m_assets.end()) {
        return std::static_pointer_cast<T>(asset->second);
    }

    auto asset = std::move(LoadAssetInternal(_path));
    if (!asset) {
        return nullptr;
    }

    m_assets[_path] = std::move(asset);

    return std::static_pointer_cast<T>(m_assets[_path]);
}

问题是,当我调用 LoadAsset 方法时,返回的 shared_ptr 变量总是有 2 个强引用,当我删除持有资源的变量时,引用计数变为 1,并且资源在程序结束时永远不会释放。

示例:

auto tex = LoadAsset<Texture>("Data/Textures/Foo.tga"); // Strong refs = 2
tex = nullptr; // Strong refs = 1 and the loaded Foo.tga is never freed.

【问题讨论】:

  • 你能发一个minimal reproducible example吗?
  • 您想避免只阅读那些您知道有人仍在积极使用它们的资源(否则,您愿意重新加载资源)?然后在缓存中只保留资源的weak_ptr
  • 共享对象有两个所有者 - tex 和您的缓存表。
  • 如果您不希望 m_assets 容器保持对象处于活动状态,请在其中存储 weak_ptr 而不是 shared_ptr。否则,您需要从资产缓存中显式删除引用。

标签: c++ std shared-ptr


【解决方案1】:

只需创建一个在游戏主循环结束时运行的函数。像这样的

void PurgeAssets() {
    for (auto i = m_assets.begin(); i != m_assets.end();) {
        if (i->second.unique()) {
            i = m_assets.erase(i);
        }
        else {
            ++i;
        }
    }
}

【讨论】:

  • 您的解决方案确实有效,我将 PurgeAssets 从 30 帧调用到 30 帧。
  • 如果这就是你想要的,只删除引用计数为 1 的项目,你为什么要存储 shared_ptrs 而不是 weak_ptrs?
猜你喜欢
  • 1970-01-01
  • 2016-01-02
  • 2013-07-11
  • 2015-06-24
  • 2023-03-29
  • 1970-01-01
  • 2012-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多