当只剩下一个引用时,删除由shared_ptr管理的对象

时间:2015-03-29 16:30:01

标签: c++

我有std::map<const char*, std::shared_ptr<Resource, ResourceDeleter>>,其作用类似于ResourceDatabase。当有人请求std::map中已有的资源时,会插入std::map中的项目(否则将从std::map投放)。同样,当不再使用资源时,应将其删除。在ResourceDeleter中,我将从std::map中删除记录。问题是永远不会调用ResourceDeleter,因为std::shared_ptr中仍有一个std::map。将项目插入std::map后,将始终有2个std::shared_ptr - 一个用于需要资源的代码,另一个用于std::map。删除第一个std::shared_ptr后,我需要从std::map删除资源。

2 个答案:

答案 0 :(得分:2)

您应该在std :: map中使用std::weak_ptr

#include <iostream>
#include <memory>

struct A {
  std::string hello() { return "hello"; }
  ~A() { std::cout << "Destructor ~A() called" << std::endl; }
};

void use(std::weak_ptr<A> const& wp)
{
  if (auto spt = wp.lock())
  {
    std::cout << "Accessing object... " << spt->hello() << "\n";
  }
  else
  {
    std::cout << "use(): object was deleted\n";
  }
}

int main()
{
  std::weak_ptr<A> wp;
  {
    std::shared_ptr<A> sp = std::make_shared<A>();
    wp = sp;
    use(wp);
    std::cout << "Destructing sp" << std::endl;
  }
  use(wp);
  std::cout << "Destructing wp" << std::endl;
}

输出:

  

访问对象...你好   破坏sp
  析构函数~A()称为
  use():对象被删除
  破坏wp

答案 1 :(得分:1)

我理解这个问题,目标是当删除最后一个指向资源的共享指针时,应该从ResourceMap中删除资源然后删除。正如您所说,如果资源的共享指针保留在ResourceMap中,则无法工作,因为映射中的共享指针始终是资源的最后一个共享指针。

所以有两个简单的解决方案。一种是在Map中保留一个弱指针(std::weak_ptr)到资源。另一个可能更简单的解决方案是在ResourceMap中保留资源本身。在这两种情况下,您都需要包装std::map(或std::unordered_map),因为您需要返回一个指向Resource的共享指针,该指针不是关联容器的mapped_type

资源可以使用map直接构建到map::emplace

实际上实现ResourceDeleter并不简单,因为要进行删除,您需要访问映射和键(或者值的迭代器)。 指向该值的指针(即shared_ptr中的内容)显然是不够的。

为了减少shared_ptr的大小,我考虑将shared_pointer的对象作为迭代器或指向std::pair<const key_type, mapped_type>的指针。然后你需要一个智能指针周围的包装器,这样*运算符最终将被实现为p->second而不是*p