unique_ptr 独占所有权 90%使用
无计数机制
std::make_unique<int>(100); 创建对象 单个变量int up1=100
std::move转移所有权,原指针变为空
unique_ptr::reset() 释放对象、原始指针
cpp
#include <iostream>
#include <memory>
int main() {
std::cout << "=== unique_ptr 演示 ===\n";
// 创建时:我是唯一的主人
std::unique_ptr<int> up1 = std::make_unique<int>(100);
std::cout << "创建up1,值是: " << *up1 << std::endl;
// 不能直接拷贝!会编译错误
// std::unique_ptr<int> up2 = up1; // ❌ 错误!
// 只能转移所有权
std::unique_ptr<int> up2 = std::move(up1); // 所有权转移
std::cout << "转移后: ";
if (up1) {
std::cout << "up1有值: " << *up1 << std::endl;
} else {
std::cout << "up1为空(所有权已转移)\n"; // 执行这里
}
if (up2) {
std::cout << "up2有值: " << *up2 << std::endl; // 执行这里
}
return 0;
// up2超出作用域,自动删除管理的对象
}
shared_ptr 共享所有权
创建对象时计数,拷贝赋值共享数量,
std::shared_ptr<T> ptr = std::make_shared<T>(构造参数); 创建对象
shared_ptr.use_count(); 返回当前共享对象所有权的 shared_ptr 数量 强引用计数
res2.reset(); 提前释放智能指针及资源
cpp
#include <iostream>
#include <memory>
int main() {
std::cout << "=== shared_ptr 引用计数演示 ===\n";
// 步骤1:创建第一个shared_ptr
std::shared_ptr<int> sp1 = std::make_shared<int>(42);
std::cout << "创建sp1后,引用计数: " << sp1.use_count() << std::endl; // 输出: 1
// 步骤2:通过拷贝构造创建第二个shared_ptr
std::shared_ptr<int> sp2 = sp1; // 拷贝构造,共享所有权
std::cout << "创建sp2(sp1的拷贝)后,引用计数: " << sp1.use_count() << std::endl; // 输出: 2
// 步骤3:通过赋值创建第三个shared_ptr
std::shared_ptr<int> sp3;
sp3 = sp1; // 赋值操作,共享所有权
std::cout << "sp3 = sp1后,引用计数: " << sp1.use_count() << std::endl; // 输出: 3
// 步骤4:sp2被重新赋值(指向新对象)
sp2 = std::make_shared<int>(100); // sp2不再共享,指向新对象
std::cout << "sp2指向新对象后,sp1的引用计数: " << sp1.use_count() << std::endl; // 输出: 2
// 步骤5:sp3超出作用域(在代码块内)
{
std::shared_ptr<int> sp4 = sp1; // 在代码块内创建
std::cout << "在代码块内创建sp4后,引用计数: " << sp1.use_count() << std::endl; // 输出: 3
} // sp4超出作用域,自动销毁
std::cout << "sp4销毁后,引用计数: " << sp1.use_count() << std::endl; // 输出: 2
return 0;
// sp1和sp3超出作用域,引用计数从2减到0,对象被销毁
}
详细计数过程表格
| 步骤 | 操作 | sp1计数 | sp2计数 | sp3计数 | 说明 |
|---|---|---|---|---|---|
| 1 | sp1 = make_shared(42) |
1 | - | - | 创建对象,计数=1 |
| 2 | sp2 = sp1 |
2 | 2 | - | 拷贝构造,两个指针共享,计数=2 |
| 3 | sp3 = sp1 |
3 | 3 | 3 | 赋值操作,三个指针共享,计数=3 |
| 4 | sp2 = make_shared(100) |
2 | 1 | 2 | sp2指向新对象,原对象计数减1 |
| 5 | 创建sp4(在代码块内) | 3 | 1 | 3 | 又一个共享者 |
| 6 | sp4销毁(代码块结束) | 2 | 1 | 2 | sp4超出作用域,计数减1 |
| 7 | main结束,所有指针销毁 | 0 | 0 | 0 | 对象被正确删除 |
weak_ptr 弱引用
创建std::weak_ptr<int> wp1 = sp1 添加弱引用计数(增加) 【强引用不变】
通过 lock() 获取临时 shared_ptr 此时强引用计数增加 【弱引用不变】
退出{}代码块时临时强引用解析计数-1
sp1.reset(); 手动提前释放,不写在main结尾也会自动释放的
std::shared_ptr的控制块维护两个计数器:强引用计数:
shared_ptr的数量,决定对象何时被销毁弱引用计数:
weak_ptr的数量,决定控制块本身何时被销毁
cpp
#include <iostream>
#include <memory>
int main() {
std::cout << "=== weak_ptr 弱引用计数演示 ===\n";
// 步骤1:创建shared_ptr
std::shared_ptr<int> sp1 = std::make_shared<int>(999);
/* 强引用计数 = 1 弱引用计数 = 0 对象状态:存活*/
std::cout << "创建sp1后 - 强引用计数: " << sp1.use_count() << std::endl; // 输出: 1
// 步骤2:创建weak_ptr(不增加强引用计数!)
std::weak_ptr<int> wp1 = sp1;
/*强引用计数 = 1(不变)弱引用计数 = 1(增加)对象状态:存活*/
std::cout << "创建wp1(来自sp1)后 - 强引用计数: " << sp1.use_count(); // 输出: 1(不变!)
// 注意:use_count()只返回强引用计数,弱引用计数是隐藏的
// 步骤3:通过weak_ptr获取shared_ptr
{
std::shared_ptr<int> sp2 = wp1.lock(); // 如果对象还存在,获取shared_ptr
if (sp2) {
std::cout << ", 通过wp1.lock()成功,强引用计数: " << sp1.use_count() << std::endl; // 输出: 2
}
} // sp2销毁
/*进入块时:强引用计数 = 2(sp1 + sp2) 弱引用计数 = 1 对象状态:存活*/
/*退出块时(sp2析构):强引用计数 = 1(sp1)弱引用计数 = 1 对象状态:存活*/
std::cout << "sp2销毁后 - 强引用计数: " << sp1.use_count() << std::endl; // 输出: 1
// 步骤4:原始shared_ptr销毁
sp1.reset(); // 手动销毁sp1
std::cout << "sp1.reset()后 - sp1的use_count(): " << sp1.use_count() << std::endl; // 输出: 0
// 步骤5:尝试通过已失效的weak_ptr获取对象
std::shared_ptr<int> sp3 = wp1.lock();
/*强引用计数 = 0 → 对象被销毁弱引用计数 = 1(wp1仍存在)对象状态:已销毁,但控制块仍在*/
if (sp3) {
std::cout << "成功获取对象\n";
} else {
std::cout << "对象已被销毁,获取失败\n"; // 执行这里
}
return 0;
}
/* 强引用计数 = 1 弱引用计数 = 0 对象状态:存活*/
std::shared_ptr<int> sp1 = std::make_shared<int>(999);
/*强引用计数 = 1(不变)弱引用计数 = 1(增加)对象状态:存活*/std::weak_ptr<int> wp1 = sp1;
/*进入块时:强引用计数 = 2(sp1 + sp2) 弱引用计数 = 1 对象状态:存活*//*退出块时(sp2析构):强引用计数 = 1(sp1)弱引用计数 = 1 对象状态:存活*/
{
std::shared_ptr<int> sp2 = wp1.lock(); // 如果对象还存在,获取shared_ptr
if (sp2) {
std::cout << ", 通过wp1.lock()成功,强引用计数: " << sp1.use_count() << std::endl; // 输出: 2
}
} // sp2销毁
/*提前释放资源,冗余操作,在main结尾会自动释放*//*强引用计数 = 0 → 对象被销毁弱引用计数 = 1(wp1仍存在)
sp1.reset(); // 手动销毁sp1
/*强引用计数 = 0 → 对象被销毁弱引用计数 = 1(wp1仍存在)对象状态:已销毁,但控制块仍在*///尝试通过已失效的weak_ptr获取对象
std::shared_ptr<int> sp3 = wp1.lock();
if (sp3) {
std::cout << "成功获取对象\n";
} else {
std::cout << "对象已被销毁,获取失败\n"; // 执行这里
}