为什么"weak.lock()" return "nullptr" 和"auto weak=std::make_shared<int>(42);" 的定义一样?

Why does "weak.lock()" return "nullptr" with the definition of "auto weak=std::make_shared<int>(42);"?

为什么 weak.lock() return nullptr 在此代码片段中:

   std::weak_ptr<int> weakPtr1 = std::make_shared<int>(6);
   std::cout << weakPtr1.lock() << std::endl;

而它适用于以下一个:

   std::shared_ptr<int> sharedPtr = std::make_shared<int>(99);
   std::weak_ptr<int> weakPtr2 = sharedPtr;
   std::cout << weakPtr2.lock() << std::endl;

检查 cpp.sh/9gkys.

想来想去,现在还是一头雾水。如果能为这个问题提供一些帮助,我将不胜感激。

您的示例使用复制初始化。因此,在右侧构造的 shared_ptr 仅在表达式求值之前存在,然后被销毁:

  1. 在第一个示例中,这意味着不再有对 shared_ptr 的引用(我们不计算弱引用),因此 lock returns null.
  2. 在第二个中,您将结果绑定到一个局部变量,将生命周期延长到当前块 - 因此仍然有一个引用,并且没有空结果。

智能指针,为了正常工作,维护一个所谓的控制块作为元数据存储,特别是使用计数器。也就是说,每个资源在内存中都有一个关联的控制块(由例如两个整数组成),智能指针可以引用它来了解其中有多少仍然是 using/observing 资源。显然,每个现有的 std::shared_ptr 都会增加存储在控制块中的使用计数器,以便其析构函数知道是否该在销毁时释放资源。 std::weak_ptr,反过来,只跟踪对象及其控制块。请注意,这里有一个重要的细节:std::weak_ptr 不会增加使用计数器。这是可取的,因为它的主要目的是打破一对观察彼此的对象之间可能的循环。也就是说,如果两个对象将 std::shared_ptr 存储到另一个对象,那么这样一对对象也将无限地保持另一个对象。

std::weak_ptr 如何知道资源是否可以 lock()ed?只有当使用计数器大于零时,这才能成功。它从控制块知道这一点(只要还有非零弱指针观察它,它本身就会在内存中保持活动状态)。

在第一个例子中:

std::weak_ptr<int> weakPtr1 = std::make_shared<int>(6);

同时分配了一个资源 (int=6) 及其控制块。使用计数器变成 1,只要 std::shared_ptr 还活着,它就会保持不变。然后,初始化一个std::weak_ptr,得到一个指向控制块的指针。在这里,它不会增加使用计数器。但是,它会增加弱指针的计数器。此时,两个计数器都是1。然后,在分号 ; 处,临时 std::shared_ptr 被销毁。它将使用计数器减少到 0。这意味着不再有共享指针共享资源的所有权,从而允许释放该资源。但是,仍然有1弱指针在观察控制块,这意味着控制块本身将保留在内存中,因此weakPtr1知道它无法lock()资源不再存在(因为该资源不再存在)。

在第二个例子中:

std::shared_ptr<int> sharedPtr = std::make_shared<int>(99);
std::weak_ptr<int> weakPtr2 = sharedPtr;

资源int=99及其控制块都保持活动状态。因此,只要 sharedPtr(或其任何副本)未被破坏,weakPtr2 就可以被锁定。