简体   繁体   English

weak_ptr在shared_ptr中的作用

[英]Role of weak_ptr in shared_ptr

I understand how a shared_ptr works except for the role of the weak_ptr. 我理解shared_ptr如何工作,除了weak_ptr的角色。 I understand its there to detect circular references when the reference count isn't zero, but beyond this I don't understand just exactly how it does this. 我理解它在那里检测循环引用时引用计数不为零,但除此之外,我不明白它究竟是如何做到的。 What does it do? 它有什么作用?

See also: When is std::weak_ptr useful? 另请参见: std :: weak_ptr何时有用? for why and How does weak_ptr work? 为什么以及weak_ptr如何工作? for how. 如何。

I'll provide an example of how I've seen it used, though the sample code I whipped up is a bit convoluted so bear with me: 我将举例说明我如何使用它,虽然我掀起的示例代码有点令人费解,所以请耐心等待:

#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;
}

Here we have a container that contains some shared resource - ints in this case - ( shared_ptr ), that another container needs to reference ( weak_ptr ). 在这里,我们有一个包含一些共享资源的容器 - 在这种情况下为 - ( shared_ptr ),另一个容器需要引用( weak_ptr )。 The referencing does not own the resource, it only needs to be able to access it if it exists . 引用不拥有资源,只需要能够访问它( 如果存在) In order to tell if the resource being referenced is still alive, we convert the weak_ptr to a shared_ptr using weak_ptr::lock() . 为了判断被引用的资源是否仍然存在,我们使用weak_ptr::lock()weak_ptr转换为shared_ptr Those resources that still exist will have a valid shared_ptr returned by lock() . 那些仍然存在的资源将具有lock()返回的有效shared_ptr Those that no longer exist will return a null shared_ptr . 那些不再存在的将返回null shared_ptr shared_ptr has an operator bool() that we can use to check if it is null or not before attempting to use it. shared_ptr有一个operator bool() ,我们可以在尝试使用它之前检查它是否为null。

A less convoluted scenario might be if you were making a game where every object in the game was represented by a game_object . 如果你制作的游戏中游戏中的每个对象都由game_object代表,那么一个不太复杂的场景可能就是game_object Say you have some kind of seeking logic for an enemy which requires a target game_object to seek to. 假设你有一种寻求敌人的逻辑,这需要一个目标game_object来寻求。 Using the above, you could have the enemy hold onto a weak_ptr<game_object> . 使用上面的方法,你可以让敌人抓住一个weak_ptr<game_object> It doesn't own this game_object . 它不拥有这个game_object If something else kills its target, its target should die; 如果其他东西杀死其目标,其目标应该死亡; not hang in some limbo state which would happen if the enemy held a shared_ptr instead. 如果敌人持有一个shared_ptr而不会陷入某种不稳定状态。 This way if the enemy's target is still alive (which it can check by locking the weak_ptr ), it can execute the seeking logic; 这样,如果敌人的目标仍然存活(可以通过锁定weak_ptr来检查),它可以执行搜索逻辑; otherwise it can find a new target. 否则它可以找到新的目标。 The "owner" of the game_object could be some sort of game_world class - this would have a container of shared_ptr<game_object> . game_object的“所有者”可能是某种类型的game_world类 - 这将有一个shared_ptr<game_object>的容器。 When the enemy needs a new target it could search through this container and create its weak_ptr from the game_world 's shared_ptr . 当敌人需要一个新目标时,它可以搜索这个容器并从game_worldshared_ptr创建它的weak_ptr

Weak pointers don't claim ownership of a resource, but only refer to it. 弱指针不声明资源的所有权,而只是引用它。 Thus, they don't allow you to operate on a resource in any way except claiming the ownership once again (with the weak_ptr::lock() method). 因此,它们不允许您以任何方式对资源进行操作,除了再次声明所有权(使用weak_ptr::lock()方法)。 IMHO, the most frequent real-life situations where such a behaviour is desires are cyclic dependencies and (less frequently) caching. 恕我直言,这种行为所需的最常见的现实生活情况是循环依赖和(较不频繁)缓存。

Cyclic dependencies made with shared pointers only are de facto memory leaks, because mutual reference counts of the pointers will never be less than 1: if nothing else owns A, then B still does, and vice versa. 使用共享指针进行的循环依赖只是事实上的内存泄漏,因为指针的相互引用计数永远不会小于1:如果没有别的东西拥有A,那么B仍然会这样做,反之亦然。 A weak pointer doesn't 'detect' this situation. 弱指针不能“检测”这种情况。 It just won't let the trouble in, simply by breaking the loop of ownership. 只是通过打破所有权循环,它不会让麻烦进入。 You might still 'connect the ends of the chain' by locking the weak pointer, but none of the shared pointers that you might obtain via the weak one will persist. 您可能仍然通过锁定弱指针来“连接链的末端”,但是您可能通过弱指针获得的共享指针都不会持久存在。

The problem with caching is, yet again, that a cache usually shouldn't affect lifetime of the cached content, it is not a duty of the cache. 缓存的问题是,缓存通常不应该影响缓存内容的生命周期,它不是缓存的职责。 But, if the cache would hold shared pointers, then you wouldn't be able to terminate the lifetime of a cached object without having to talk to the cache, which is often inconvenient. 但是,如果缓存将保存共享指针,那么您将无法终止缓存对象的生命周期而无需与缓存进行通信,这通常很不方便。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM