4

除了weak_ptr 的作用外,我了解shared_ptr 的工作原理。我知道当引用计数不为零时它可以检测循环引用,但除此之外我不明白它是如何做到这一点的。它有什么作用?

4

2 回答 2

3

另请参阅:std::weak_ptr 何时有用?为什么以及weak_ptr如何工作?如何。

我将提供一个示例来说明我是如何使用它的,尽管我编写的示例代码有点复杂,所以请耐心等待:

#include <vector>
#include <memory>
#include <ostream>

int main()
{
  // Fill container with values 1-50. This container OWNS these values.
  std::vector<std::shared_ptr<int>> owning_container;
  for(int i = 1; i <= 50; ++i)
  {
    owning_container.emplace_back(std::make_shared<int>(i));
  }

  // Create a sepearate container that references all owned values that are multiples of 5.
  std::vector<std::weak_ptr<int>> referencing_container;
  for(std::shared_ptr<int> const& i : owning_container)
  {
    if((*i) % 5 == 0)
    {
      // Make weak_ptr that references shared_ptr
      referencing_container.emplace_back(i);
    }
  }

  // Go through the owned values and delete all that are multiples of 10.
  for(auto it = owning_container.begin(); it != owning_container.end();)
  {
    std::shared_ptr<int> const& i = *it;
    if(*i % 10 == 0)
    {
      it = owning_container.erase(it);
    }
    else
    {
      ++it;
    }
  }

  // Now go through the referencing container and print out all values.
  // If we were dealing with raw pointers in both containers here we would access deleted memory,
  //   since some of the the actual resources (in owning_container) that referencing_container
  //   references have been removed.
  for(std::weak_ptr<int> const& i_ref : referencing_container)
  {
    // Check if the shared resource still exists before using it (purpose of weak_ptr)
    std::shared_ptr<int> i = i_ref.lock();
    if(i)
    {
      std::cout << *i << std::endl;
    }
  }

  return 0;
}

这里我们有一个包含一些共享资源的容器 - 在这种情况下是整数 - ( shared_ptr),另一个容器需要引用 ( weak_ptr)。引用不拥有资源,它只需要能够访问它(如果它存在)。为了判断被引用的资源是否仍然存在,我们将 转换weak_ptrshared_ptrusing weak_ptr::lock()。那些仍然存在的资源将有一个shared_ptrlock(). 那些不再存在的将返回 null shared_ptrshared_ptr有一个operator bool()我们可以在尝试使用它之前检查它是否为空。

一个不太复杂的场景可能是,如果您正在制作一个游戏,其中游戏中的每个对象都由game_object. 假设您有某种寻找敌人的逻辑,需要game_object寻找目标。使用上述方法,您可以让敌人抓住weak_ptr<game_object>. 它不拥有这个game_object。如果别的东西杀死了它的目标,它的目标应该死;不要陷入某种僵局,如果敌人持有 a 会发生这种情况shared_ptr。这样,如果敌人的目标还活着(可以通过锁定 来检查weak_ptr),它可以执行搜索逻辑;否则它可以找到一个新的目标。的“所有者”game_object可能是某种game_world类 - 这将有一个容器shared_ptr<game_object>. 当敌人需要一个新目标时,它可以搜索这个容器并weak_ptrgame_world.shared_ptr

于 2014-08-09T22:49:41.747 回答
2

弱指针不声明资源的所有权,而只是引用它。因此,它们不允许您以任何方式对资源进行操作,除非再次声明所有权(使用weak_ptr::lock()方法)。恕我直言,这种行为是欲望的最常见的现实生活情况是循环依赖和(不太频繁)缓存。

仅使用共享指针产生的循环依赖实际上是内存泄漏,因为指针的相互引用计数永远不会小于 1:如果没有其他东西拥有 A,那么 B 仍然拥有,反之亦然。弱指针不会“检测”这种情况。它只是不会让麻烦进来,只需打破所有权循环。您仍然可以通过锁定弱指针来“连接链的末端”,但是您可能通过弱指针获得的共享指针都不会持续存在。

缓存的问题再次是,缓存通常不应该影响缓存内容的生命周期,这不是缓存的职责。但是,如果缓存将保存共享指针,那么您将无法终止缓存对象的生命周期而无需与缓存通信,这通常很不方便。

于 2014-08-10T22:53:37.173 回答