【问题标题】:Pass an object to a function expecting shared_ptr without actually sharing ownership将对象传递给期望 shared_ptr 的函数而不实际共享所有权
【发布时间】:2012-08-26 05:06:39
【问题描述】:

首先,我确实意识到这与 shared_ptr 的目的完全矛盾。我正在处理一些库代码,其中 ParticleSystem 的实例期望在构造期间将 shared_ptr 传递给它们以设置用于每个粒子的纹理。问题是,我已经以我的纹理拥有具体所有权的方式构建了我的程序的其余部分(如果这是正确的术语)——TextureCache 拥有所有纹理。所以我需要一种方法来使用这个 ParticleSystem 类,而不允许它删除我的纹理。如果我要简单地创建一个像ParticleSystem(std::shared_ptr<Texture>&myTexture) 这样的新实例,那么它会在纹理被破坏时尝试破坏它(这是一个不需要且无效的操作,因为我的纹理甚至不是用new 创建的)。

我在这个问题上看到的最简洁的方法是这样的:

  1. 在创建 ParticleSystem 的函数中创建一个包含纹理的 shared_ptr。
  2. 然后使用placement new,在与我刚刚创建的shared_ptr 相同的内存位置重建shared_ptr。现在纹理的引用计数为 2。
  3. 创建粒子系统。
  4. 让 shared_ptr 超出范围。由于它是在堆栈上分配的,所以它的解构器将被调用,并且它只会将引用计数减 1。因此对象的引用计数将始终比实际值大 1,因此它永远不会被自动销毁。

我相信这个解决方案是合理的,但它仍然令人难以置信的骇人听闻。有没有更好的方法来解决我的问题?

【问题讨论】:

  • 为什么你的纹理缓存中没有 shared_ptrs?
  • @Vaughn 是可行的,但是通过跟踪指向纹理的指针而不是纹理本身,这似乎是不必要的额外间接级别,并且这将在语义上滥用共享指针,因为纹理缓存是仍然负责决定何时可以发布纹理 - 它不会共享​​>所有权。

标签: c++ memory-management shared-ptr


【解决方案1】:

如果您想将非托管指针(由您自己管理)传递给需要智能指针的代码,例如shared_ptr,您可以通过别名创建空但不为空的shared_ptr 来禁用“智能”指针功能构造函数:

Texture* unmanagedPointer = ...
shared_ptr<Texture> smartPointer(shared_ptr<Texture>(), unmanagedPointer);

此解决方案比其他人建议的自定义删除器更有效且更短,因为没有进行控制块分配和引用计数。

一些额外的细节可以在这里找到:

What is the difference between an empty and a null std::shared_ptr in C++?

How to avoid big memory allocation with std::make_shared

【讨论】:

    【解决方案2】:

    您可以使用custom deleter that does nothing 创建shared_ptr。这将防止删除此 shared_ptr 拥有的纹理。

    struct null_deleter
    {
        void operator()(void const *) const
        {
        }
    };
    
    shared_ptr<Texture> CreateTexture(Texture* myTexture)
    {
        shared_ptr<Texture> pTexture(myTexture, null_deleter());
        return pTexture;
    }
    

    【讨论】:

      【解决方案3】:

      shared_ptr 允许您提供自定义删除器。所以shared_ptr 可用于使用 malloc 分配的内存或您正在使用的任何内存分配方案,您甚至可以使用它来自动解锁互斥锁或关闭文件,但我离题了。你可以创建一个带有空删除器的shared_ptr,当它的引用计数达到0时它不会做任何事情。

      【讨论】:

        【解决方案4】:

        按照 Vaughn Cato 的建议,将 shared_ptr 存储在您的缓存中。为了在没有人使用时从缓存中删除纹理,只需检查shared_ptruse_count 函数是否返回1,这意味着缓存是唯一的所有者

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-03-22
          • 1970-01-01
          • 2018-09-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多