为什么“weak.lock()”返回“nullptr”,定义为“auto weak=std::make_shared<int>(42);”?

Joh*_*ohn 5 c++ smart-pointers

为什么在这段代码片段中weak.lock()返回nullptr

   std::weak_ptr<int> weakPtr1 = std::make_shared<int>(6);
   std::cout << weakPtr1.lock() << std::endl;
Run Code Online (Sandbox Code Playgroud)

而它在以下情况下工作:

   std::shared_ptr<int> sharedPtr = std::make_shared<int>(99);
   std::weak_ptr<int> weakPtr2 = sharedPtr;
   std::cout << weakPtr2.lock() << std::endl;
Run Code Online (Sandbox Code Playgroud)

检查 cpp.sh/9gkys。

我曾经想过,想过,但我现在仍然很困惑。我将不胜感激能在这个问题上得到一些帮助。

Pio*_*cki 4

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

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

在第一个示例中:

std::weak_ptr<int> weakPtr1 = std::make_shared<int>(6);
Run Code Online (Sandbox Code Playgroud)

资源(int=6)及其控制块都被分配。使用计数器变为1,并且只要还std::shared_ptr活着,就保持这种状态。然后,astd::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;
Run Code Online (Sandbox Code Playgroud)

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