一篇搞懂C++ STL 智能指针监视器std::weak_ptr
@TOC
前言
在 C++ 中,智能指针是管理动态分配内存的有效工具。除了 std::shared_ptr
和 std::unique_ptr
,C++11 还引入了 std::weak_ptr
。它是一个辅助智能指针,用于解决 std::shared_ptr
引用计数可能引发的循环引用问题。std::weak_ptr
不管理对象的生命周期,只是提供对由 std::shared_ptr
管理的对象的非拥有访问权。
为什么使用 std::weak_ptr
- 避免循环引用:
std::weak_ptr
可以打破std::shared_ptr
引用计数的循环引用问题。通过不增加引用计数,避免了内存泄漏。 - 延迟访问:
std::weak_ptr
可以在需要的时候访问std::shared_ptr
管理的对象,而不强制要求对象必须存在。 - 观察者模式:
std::weak_ptr
用于实现观察者模式,当对象的生命周期不被观察者所延续时很有用。
std::weak_ptr
与 std::shared_ptr
和 std::unique_ptr
的区别
-
所有权管理:
std::unique_ptr
:独占所有权,不能共享。std::shared_ptr
:允许多个智能指针共享同一个对象的所有权,通过引用计数管理生命周期。std::weak_ptr
:不拥有对象,只是观察者,不影响对象的生命周期。
-
引用计数:
std::unique_ptr
:没有引用计数。std::shared_ptr
:使用引用计数来管理对象的生命周期。std::weak_ptr
:不参与引用计数管理,仅通过std::shared_ptr
访问。
std::weak_ptr
的构造函数和操作函数
构造函数
-
默认构造函数
std::weak_ptr();
std::weak_ptr<int> w; // 创建一个空的 weak_ptr
-
构造函数(
std::shared_ptr
)std::weak_ptr(const std::shared_ptr<T>& r);
std::shared_ptr<int> s(new int(10)); std::weak_ptr<int> w(s); // 从 shared_ptr 构造 weak_ptr
成员函数
-
lock
std::shared_ptr<T> lock() const;
std::shared_ptr<int> s(new int(20)); std::weak_ptr<int> w(s); std::shared_ptr<int> p = w.lock(); // 获取 shared_ptr,如果对象仍然存在 if (p) { std::cout << "Object is still alive: " << *p << std::endl; } else { std::cout << "Object has been destroyed" << std::endl; }
-
expired
bool expired() const noexcept;
std::shared_ptr<int> s(new int(30)); std::weak_ptr<int> w(s); if (w.expired()) { std::cout << "Object has been destroyed" << std::endl; } else { std::cout << "Object is still alive" << std::endl; }
-
reset
void reset();
std::shared_ptr<int> s(new int(40)); std::weak_ptr<int> w(s); w.reset(); // 释放对原对象的观察
如果有多个 std::shared_ptr
指向同一内存
多个 std::shared_ptr
实例可以共享对同一对象的所有权,通过引用计数来管理对象的生命周期。当最后一个 std::shared_ptr
被销毁时,对象会被释放。std::weak_ptr
可以观察这些 std::shared_ptr
管理的对象,但不参与引用计数的管理,因此不会影响对象的生命周期。
std::shared_ptr<int> p1(new int(50));
std::shared_ptr<int> p2 = p1; // 共享所有权
std::weak_ptr<int> w(p1); // 观察 p1 管理的对象
std::cout << "Use count: " << p1.use_count() << std::endl; // 引用计数
p1.reset(); // 释放 p1 的所有权
if (auto p = w.lock()) { // 尝试获取对象
std::cout << "Object is still alive: " << *p << std::endl;
} else {
std::cout << "Object has been destroyed" << std::endl;
}
p2.reset(); // 释放 p2 的所有权,对象将被销毁
示例代码
下面的示例展示了 std::weak_ptr
的各种构造函数和操作函数的用法:
#include <iostream>
#include <memory>
struct MyClass {
MyClass(int v) : value(v) {}
int value;
void display() const { std::cout << "Value: " << value << std::endl; }
};
int main() {
// 使用默认构造函数
std::weak_ptr<int> w1;
// 使用 std::shared_ptr 构造函数
std::shared_ptr<int> s1(new int(10));
std::weak_ptr<int> w2(s1); // 从 shared_ptr 构造 weak_ptr
// 使用 lock 函数
std::shared_ptr<int> p1 = w2.lock();
if (p1) {
std::cout << "p1: " << *p1 << std::endl;
}
// 使用 expired 函数
std::cout << "w2 expired: " << w2.expired() << std::endl;
// 使用 reset 函数
w2.reset(); // 释放对原对象的观察
std::cout << "w2 expired after reset: " << w2.expired() << std::endl;
// 演示多个 shared_ptr 和 weak_ptr
std::shared_ptr<MyClass> s2(new MyClass(20));
std::weak_ptr<MyClass> w3(s2);
std::cout << "Use count of s2: " << s2.use_count() << std::endl;
if (auto p2 = w3.lock()) { // 尝试获取对象
p2->display();
}
s2.reset(); // 释放 s2 的所有权
if (auto p3 = w3.lock()) { // 尝试获取对象
p3->display();
} else {
std::cout << "Object has been destroyed" << std::endl;
}
return 0;
}
简单来说
std::weak_ptr
的主要作用就是用来观察由 std::shared_ptr
管理的对象,而不会影响对象的引用计数。这使得 std::weak_ptr
在处理可能的循环引用或在需要查看对象是否仍然存在的情况下非常有用。
总结
std::weak_ptr
是一个辅助智能指针,用于避免 std::shared_ptr
的循环引用问题,并在对象的生命周期结束时提供安全的访问。它通过引用计数来观察 std::shared_ptr
管理的对象,但不会影响对象的生命周期。理解 std::weak_ptr
的构造函数和操作函数,有助于在需要解决引用计数循环问题和实现观察者模式时更有效地管理内存。
- 点赞
- 收藏
- 关注作者
评论(0)