在现代 C++ 工程中,shared_ptr 常用于多个模块共享资源,但这也引入一个严重隐患——循环引用(reference cycle),即两个对象相互持有 shared_ptr 指针,导致它们永远不会释放。
解决方案正是:weak_ptr —— 弱引用观察者,它不拥有资源,只用于访问和判断对象是否还存在。
本篇将:
WeakPtr<T> 与 SharedPtr<T> 配合使用cpp复制编辑structNode {
std::shared_ptr<Node> next;
};
intmain() {
auto a = std::make_shared<Node>();
auto b = std::make_shared<Node>();
a->next = b;
b->next = a; // ❌ a 和 b 永远不会释放
}
因为它们互相持有对方的 shared_ptr,导致引用计数永远为 1。
weak_ptrcpp复制编辑structNode {
std::weak_ptr<Node> next; // ✅ 使用 weak_ptr 不增加引用计数
};
当需要使用它时:
cpp复制编辑if (auto np = node->next.lock()) {
// 使用 np,它是 shared_ptr
}
weak_ptr 并不拥有资源,而是观测 shared_ptr 是否还活着。
要支持 weak_ptr,我们需对控制块进行重构:
| 字段 | 作用 |
|---|---|
strong_count | SharedPtr 引用数 |
weak_count | WeakPtr 引用数 |
ptr | 被管理对象 |
destroyed 标志 | 用于判断资源是否已释放 |
我们要实现:
SharedPtr<T> 正常管理强引用WeakPtr<T> 共享控制块,但不增加 strong_countWeakPtr::lock() 可转换为 SharedPtr<T>(若资源未释放)cpp复制编辑template<typename T>
classControlBlock {
public:
T* ptr;
size_t strong_count = 1;
size_t weak_count = 0;
ControlBlock(T* p) : ptr(p) {}
~ControlBlock() = default;
voidreleaseStrong() {
if (--strong_count == 0) {
delete ptr;
ptr = nullptr;
if (weak_count == 0) deletethis;
}
}
voidreleaseWeak() {
if (--weak_count == 0 && strong_count == 0) {
deletethis;
}
}
};
cpp复制编辑template<typename T>
classSharedPtr {
ControlBlock<T>* ctrl = nullptr;
public:
SharedPtr() = default;
explicitSharedPtr(T* p) {
ctrl = newControlBlock<T>(p);
}
SharedPtr(const SharedPtr& other) {
ctrl = other.ctrl;
if (ctrl) ctrl->strong_count++;
}
~SharedPtr() {
if (ctrl) ctrl->releaseStrong();
}
SharedPtr& operator=(const SharedPtr& other) {
if (this != &other) {
if (ctrl) ctrl->releaseStrong();
ctrl = other.ctrl;
if (ctrl) ctrl->strong_count++;
}
return *this;
}
T* get()const { return ctrl ? ctrl->ptr : nullptr; }
size_tuse_count()const { return ctrl ? ctrl->strong_count : 0; }
friendclassWeakPtr<T>;
};
cpp复制编辑template<typename T>
classWeakPtr {
ControlBlock<T>* ctrl = nullptr;
public:
WeakPtr() = default;
WeakPtr(const SharedPtr<T>& sp) {
ctrl = sp.ctrl;
if (ctrl) ctrl->weak_count++;
}
WeakPtr(const WeakPtr& other) {
ctrl = other.ctrl;
if (ctrl) ctrl->weak_count++;
}
~WeakPtr() {
if (ctrl) ctrl->releaseWeak();
}
SharedPtr<T> lock()const {
if (ctrl && ctrl->strong_count > 0) {
returnSharedPtr<T>(*this);
}
returnSharedPtr<T>();
}
private:
friendclassSharedPtr<T>;
WeakPtr(ControlBlock<T>* c) : ctrl(c) {
if (ctrl) ctrl->weak_count++;
}
};
添加:
cpp复制编辑SharedPtr(const WeakPtr<T>& wp) {
ctrl = wp.ctrl;
if (ctrl && ctrl->strong_count > 0) {
ctrl->strong_count++;
} else {
ctrl = nullptr;
}
}
cpp复制编辑SharedPtr<int> sp1(newint(123));
WeakPtr<int> wp1 = sp1;
{
SharedPtr<int> sp2 = wp1.lock();
if (sp2.get()) std::cout << *sp2 << std::endl; // 输出 123
}
sp1 = SharedPtr<int>(); // 引用计数为 0,资源释放
SharedPtr<int> sp3 = wp1.lock();
if (!sp3.get()) std::cout << "对象已被释放" << std::endl;
输出:
复制编辑123 对象已被释放
lock() 返回空指针strong_count > 0本篇我们实现了一个完整的弱引用智能指针 WeakPtr<T>,它具有:
SharedPtr<T> 协同共享控制块lock() 安全获取临时所有权通过 SharedPtr + WeakPtr 的配合,我们构建了一个完整的资源管理框架,这也是现代 C++ 智能指针设计的核心理念。
/1
文章评论(0条评论)
登录后参与讨论