在C++中,weak_ptr 是一种智能指针,它用于解决 shared_ptr 之间的循环引用问题。weak_ptr 不拥有它所指向的对象,也就是说,它不会增加对象的引用计数。因此,weak_ptr 不能直接用来访问对象,但可以通过 lock() 方法尝试获取一个 shared_ptr 临时访问对象。如果对象已经被销毁,lock() 将返回一个空的 shared_ptr。


基本用法

创建 weak_ptr: weak_ptr 通常是从一个 shared_ptr 创建的。你不能直接通过 new 表达式来初始化一个 weak_ptr。

访问对象: 使用 lock() 方法获取一个 shared_ptr,然后通过这个 shared_ptr 来访问对象。如果 weak_ptr 所指向的对象已经被销毁,lock() 将返回一个空的 shared_ptr。

解引用 weak_ptr: 不能直接解引用 weak_ptr(即不能使用 * 或 -> 操作符)。

例子

#include <iostream>  
#include <memory>  
  
class MyClass {  
public:  
    MyClass() { std::cout << "MyClass created\n"; }  
    ~MyClass() { std::cout << "MyClass destroyed\n"; }  
    void sayHello() { std::cout << "Hello\n"; }  
};  
  
int main() {  
    std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>();  
    std::weak_ptr<MyClass> weakPtr = sharedPtr;  
  
    // 通过 weakPtr 访问对象  
    if (auto lockedPtr = weakPtr.lock()) {  
        lockedPtr->sayHello(); // 输出 Hello  
    } else {  
        std::cout << "Object has been destroyed\n";  
    }  
  
    // 当 sharedPtr 超出作用域并被销毁时,MyClass 对象也将被销毁  
    // 注意:这里的 weakPtr 不会阻止 MyClass 对象的销毁  
  
    // 尝试再次通过 weakPtr 访问对象  
    if (auto lockedPtr = weakPtr.lock()) {  
        lockedPtr->sayHello(); // 这将不会执行,因为对象已被销毁  
    } else {  
        std::cout << "Object has been destroyed\n"; // 这将执行  
    }  
  
    return 0;  
}

注意事项

使用 weak_ptr 时,要意识到你正在访问的对象可能在任何时候被销毁。因此,在每次访问前都应通过 lock() 方法检查对象是否还存在。

weak_ptr 主要用于解决 shared_ptr 之间的循环引用问题,但在没有循环引用风险的情况下,应谨慎使用 weak_ptr,因为它增加了代码的复杂性。

与 shared_ptr 类似,weak_ptr 也是线程安全的,但只有在所有相关的 shared_ptr 和 weak_ptr 实例都在同一内存位置(即同一个程序中)时,这种线程安全才有意义。如果 shared_ptr 和 weak_ptr 被不同的程序或不同的线程组分别管理,则可能需要额外的同步机制来确保线程安全。