【问题标题】:How to make not owning pointers like shared_ptr?如何使不拥有像 shared_ptr 这样的指针?
【发布时间】:2019-01-30 19:14:16
【问题描述】:

在我的资源管理器中,createTexture 方法应该生成一个指向纹理的指针。当只有经理拥有资源时,我想删除它。我怎样才能做到这一点?如果我使用 shared_ptr,资源管理器会将其 shared_ptr 指针存储到纹理中,并且无法删除它。

class ResourceManager
{
    vector<shared_ptr<Texture>> _textres;

public:
    shared_ptr<Texture> CreateTexture()
    {
        auto tex = shared_ptr<Texture>(new Texture);
        _textures.push_back(tex);
        return tex;
    }
}

int main
{
    ResourceManager rm;

    {
        auto tex = rm.CreateTexture();
        // Do something with texture...
    }

    // Problem here: ResourceManager doesn't remove the texture because he owns it
}

【问题讨论】:

  • 经理为什么要坚持贴图?
  • 你想要std::weak_ptr吗?
  • 一种方法(假设您不能完全摆脱_textures 向量)是让_textures 持有weak_ptr&lt;Texture&gt; 类型的对象,而不是shared_ptr&lt;Texture&gt;en.cppreference.com/w/cpp/memory/weak_ptr
  • 资源管理器必须知道所有纹理的内存使用情况。我还想在删除纹理时(在另一个线程中异步)做一个特殊的逻辑。
  • 所以你只是想让资源管理器在纹理被其他地方删除时以某种方式得到通知,而不是真正让它保持活动状态?你的特殊逻辑应该在哪个线程中执行?

标签: c++


【解决方案1】:

你需要的是:

  • weak_ptr 的向量,而不是 shared_ptr
  • shared_ptr 的删除函数(在范围内没有非弱引用时调用)在向量中查找对象并删除该条目

可以使用shared_ptr 构造函数提供自定义删除器。请务必实际执行删除操作,因为该行为将不再是自动的。

还要小心some confusions with respect to weak_ptr behaviour during deleter invocation;你总是可以switch to a raw pointer instead 这基本上具有相同的效果,没有任何紧迫的问题。

请注意,此更改使您的经理不再“拥有”纹理,但根据您描述的语义(“当只有经理拥有资源时删除资源”)它从来没有真正做到过。

【讨论】:

  • 谢谢。似乎最好的主意是存储一个原始指针,并提供自定义删除器
  • 如果你让它有点侵入类(或将类包装在帮助器中),它可以持有对自身的引用,而不必查找纹理——空间的权衡时间。
  • @metal 可以说是的,但我想你会发现有些人质疑这种自我参照的设计
  • @pushрор 基本上。不过,作为记录,我使用 weak_ptr 将其投入生产,从未遇到过问题
【解决方案2】:

我认为您要的是一个shared_ptr,它在计数减至 1 时调用回调。您的管理器在创建智能指针时在 CreateTexture() 函数中注册该回调,然后检查是否每当有人减少引用计数时调用它。

要注意的极端情况:计数将从 1 开始,然后您不想删除它。

比较一个侵入式引用计数智能指针的C++ FAQ's implementation 作为起点。摆在你面前的工作是添加一个 std::function 或其他可在正确时间调用的可调用对象。

实现智能指针可能有点棘手,尤其是当您混合线程时,但对于其他起点,您可以比较来自已标准化的boost::shared_ptrLokiSharedPtr 的实现,即在 Alexandrescu 的经典 Modern C++ Design 中进行了描述。

重新实现shared_ptr 的替代方法是使用其自定义删除器来调用回调,但您必须玩一些游戏才能使其正常工作。

【讨论】:

  • 这是否意味着我需要在构造函数中使用回调重新实现shared_ptr?
  • 是的,您将在创建智能指针时传入回调,然后在智能指针的析构函数中调用回调。
猜你喜欢
  • 1970-01-01
  • 2020-09-28
  • 2014-12-04
  • 2012-01-10
  • 1970-01-01
  • 2014-12-16
  • 2021-12-20
  • 1970-01-01
  • 2010-10-11
相关资源
最近更新 更多