为什么"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
仅在表达式求值之前存在,然后被销毁:
- 在第一个示例中,这意味着不再有对 shared_ptr 的引用(我们不计算弱引用),因此
lock
returns null.
- 在第二个中,您将结果绑定到一个局部变量,将生命周期延长到当前块 - 因此仍然有一个引用,并且没有空结果。
智能指针,为了正常工作,维护一个所谓的控制块作为元数据存储,特别是使用计数器。也就是说,每个资源在内存中都有一个关联的控制块(由例如两个整数组成),智能指针可以引用它来了解其中有多少仍然是 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
就可以被锁定。
为什么 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
仅在表达式求值之前存在,然后被销毁:
- 在第一个示例中,这意味着不再有对 shared_ptr 的引用(我们不计算弱引用),因此
lock
returns null. - 在第二个中,您将结果绑定到一个局部变量,将生命周期延长到当前块 - 因此仍然有一个引用,并且没有空结果。
智能指针,为了正常工作,维护一个所谓的控制块作为元数据存储,特别是使用计数器。也就是说,每个资源在内存中都有一个关联的控制块(由例如两个整数组成),智能指针可以引用它来了解其中有多少仍然是 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
就可以被锁定。