weak_ptr通过lock()获取shared_ptr来安全访问对象,避免悬空指针;常用于解决循环引用、实现观察者模式、缓存及对象存活检测,选择时根据是否需控制生命周期决定。

C++
weak_ptr的主要作用是在不增加对象引用计数的前提下持有对象的引用,解决循环引用的问题。当
weak_ptr尝试访问的对象已经被释放时,它会变成 expired,因此需要在使用前进行检查,避免访问悬空指针。
解决方案
使用
weak_ptr时,先通过
lock()方法尝试获取
shared_ptr。如果对象仍然存在,
lock()会返回一个有效的
shared_ptr;如果对象已经被释放,
lock()会返回一个空的
shared_ptr。
#include#include class MyObject { public: int data; MyObject(int value) : data(value) { std::cout << "MyObject constructed with data: " << data << std::endl; } ~MyObject() { std::cout << "MyObject destructed with data: " << data << std::endl; } void printData() { std::cout << "Data: " << data << std::endl; } }; int main() { std::weak_ptr weakPtr; { std::shared_ptr sharedPtr = std::make_shared (42); weakPtr = sharedPtr; // 使用 weak_ptr 访问对象 std::shared_ptr lockedPtr = weakPtr.lock(); if (lockedPtr) { lockedPtr->printData(); // 安全访问 } else { std::cout << "Object has been destroyed." << std::endl; } } // sharedPtr 超出作用域,对象被释放 // 再次尝试访问 std::shared_ptr lockedPtr = weakPtr.lock(); if (lockedPtr) { lockedPtr->printData(); } else { std::cout << "Object has been destroyed." << std::endl; // 输出此行 } return 0; }
如何避免 weak_ptr
访问悬空指针导致的崩溃?
始终在使用前检查
weak_ptr
是否有效: 使用weak_ptr.lock()
获取shared_ptr
,并检查返回的shared_ptr
是否为空。这是最核心的原则。-
注意对象生命周期: 了解对象何时可能被释放,避免在对象已经被释放后尝试访问。 虽然无法完全预测,但良好的设计可以减少意外情况。
立即学习“C++免费学习笔记(深入)”;
避免在多线程环境下出现竞争: 如果
weak_ptr
在多线程环境下使用,确保在访问前进行适当的同步,防止在检查后、访问前对象被释放。例如,使用互斥锁保护对weak_ptr
的访问。
weak_ptr
还能用于哪些场景?
除了解决循环引用,
weak_ptr还有其他一些应用场景:
观察者模式: 观察者持有对主题的
weak_ptr
,当主题被销毁时,观察者可以安全地停止观察,避免访问无效对象。缓存: 缓存可以持有对对象的
weak_ptr
,如果对象被其他地方释放,缓存可以自动清理过期条目。检测对象是否存活: 可以通过将
shared_ptr
转换为weak_ptr
,然后在稍后检查weak_ptr.expired()
来判断对象是否仍然存活。
如何选择使用 weak_ptr
还是 shared_ptr
?
选择
weak_ptr还是
shared_ptr取决于所有权关系:
shared_ptr
: 表示共享所有权。多个shared_ptr
可以指向同一个对象,只有当所有shared_ptr
都被销毁时,对象才会被释放。weak_ptr
: 表示非拥有关系。weak_ptr
可以观察对象,但不会阻止对象被释放。它只是提供了一种在对象仍然存在时访问它的方式。
如果需要控制对象的生命周期,应该使用
shared_ptr。如果只是需要观察对象,而不希望影响其生命周期,应该使用
weak_ptr。通常,循环引用需要使用
weak_ptr来打破。










