diff --git a/4.SmartPointers/item20.md b/4.SmartPointers/item20.md index 71ff3c3..fde919f 100644 --- a/4.SmartPointers/item20.md +++ b/4.SmartPointers/item20.md @@ -76,7 +76,7 @@ std::shared_ptr fastLoadWidget(WidgetID id) 有三种选择: - **原始指针**。使用这种方法,如果`A`被销毁,但是`C`继续指向`B`,`B`就会有一个指向`A`的悬空指针。而且`B`不知道指针已经悬空,所以`B`可能会继续访问,就会导致未定义行为。 -- **`std::shared_ptr`**。这种设计,`A`和`B`都互相持有对方的`std::shared_ptr`,导致的`std::shared_ptr`环状结构(`A`指向`B`,`B`指向`A`)阻止`A`和`B`的销毁。甚至`A`和`B`无法从其他数据结构被访问了(比如,`C`不再指向`B`),每个的引用计数都还是1。如果发生了这种情况,`A`和`B`都被泄漏:程序无法访问它们,但是资源并没有被回收。 +- **`std::shared_ptr`**。这种设计,`A`和`B`都互相持有对方的`std::shared_ptr`,导致的`std::shared_ptr`环状结构(`A`指向`B`,`B`指向`A`)阻止`A`和`B`的销毁。甚至`A`和`B`无法从其他数据结构访问了(比如,`C`不再指向`B`),每个的引用计数都还是1。如果发生了这种情况,`A`和`B`都被泄漏:程序无法访问它们,但是资源并没有被回收。 - **`std::weak_ptr`**。这避免了上述两个问题。如果`A`被销毁,`B`指向它的指针悬空,但是`B`可以检测到这件事。尤其是,尽管`A`和`B`互相指向对方,`B`的指针不会影响`A`的引用计数,因此在没有`std::shared_ptr`指向`A`时不会导致`A`无法被销毁。 使用`std::weak_ptr`显然是这些选择中最好的。但是,需要注意使用`std::weak_ptr`打破`std::shared_ptr`循环并不常见。在严格分层的数据结构比如树中,子节点只被父节点持有。当父节点被销毁时,子节点就被销毁。从父到子的链接关系可以使用`std::unique_ptr`很好的表征。从子到父的反向连接可以使用原始指针安全实现,因为子节点的生命周期肯定短于父节点。因此没有子节点解引用一个悬垂的父节点指针这样的风险。