1.定义
- shared_ptr 和 unique_ptr 是 C++11 引入的智能指针,用于自动管理动态内存,防止内存泄漏。它们的主要区别在于所有权语义。
2.使用
2.1 unique_ptr(独占指针)
2.1.1 简单使用
#include <memory>
// 创建独占指针
std::unique_ptr<int> ptr1 = std::make_unique<int>(42);
// 错误:不能复制
// std::unique_ptr<int> ptr2 = ptr1;
// 可以移动所有权
std::unique_ptr<int> ptr2 = std::move(ptr1); // ptr1 现在为 nullptr
// 自定义删除器
auto deleter = [](int* p) { delete p; std::cout << "deleted\n"; };
std::unique_ptr<int, decltype(deleter)> ptr3(new int(10), deleter);
2.1.2 特点
- 独占资源所有权
- 离开作用域时自动释放内存
- 支持数组版本:unique_ptr<T[]>
- 可以自定义删除器
2.2 shared_ptr(共享指针)
#include <memory>
// 创建共享指针(推荐使用 make_shared)
std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
// 可以复制,引用计数增加
std::shared_ptr<int> ptr2 = ptr1; // 引用计数: 2
std::shared_ptr<int> ptr3 = ptr2; // 引用计数: 3
// 一个指针离开作用域
{
std::shared_ptr<int> ptr4 = ptr3; // 引用计数: 4
} // ptr4 销毁,引用计数: 3
// 自定义删除器
std::shared_ptr<int> ptr4(new int(100), [](int* p) {
delete p;
std::cout << "custom delete\n";
});
2.2 shared_ptr与weak_ptr(共享指针)
- 不会增加引用计数
#include <memory>
std::shared_ptr<int> sp = std::make_shared<int>(42);
// 创建 weak_ptr
std::weak_ptr<int> wp1 = sp; // 从 shared_ptr 构造
std::weak_ptr<int> wp2;
// 赋值操作
wp2 = wp1; // ✅ 允许:weak_ptr 之间赋值
wp2 = sp; // ✅ 允许:从 shared_ptr 赋值
// wp2 = std::make_shared<int>(10); // ✅ 也可以
std::cout << "sp.use_count() = " << sp.use_count() << std::endl; // 输出: 1
// weak_ptr 赋值不会增加引用计数!
- weak_ptr 的关键方法
lock() - 安全获取 shared_ptr
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> sp = std::make_shared<int>(42);
std::weak_ptr<int> wp = sp;
// 方法1:检查后再打印
std::shared_ptr<int> locked = wp.lock();
if (locked) {
std::cout << "wp指向的值: " << *locked << std::endl;
std::cout << "引用计数: " << locked.use_count() << std::endl; // 输出: 2
} else {
std::cout << "对象已销毁" << std::endl;
}
// 方法2:使用临时变量(推荐)
if (auto sp2 = wp.lock()) {
std::cout << "值: " << *sp2 << std::endl;
}
return 0;
}
2.2.1 注意
- weak_ptr 是一个观察者。本身不存储值,只存储一个指向控制块的指针
- 必须先 lock() 获取 shared_ptr 才能访问值
- lock() 会增加引用计数(临时增加)-
- 如果对象已销毁,lock() 返回空的 shared_ptr
2.3 选择指南
- 默认使用 unique_ptr - 除非需要共享所有权
- 优先使用 make_unique/make_shared - 异常安全且高效
- 使用 shared_ptr 时注意循环引用 - 必要时使用 weak_ptr
- 避免裸指针与智能指针混用
- 不要使用 shared_ptr 管理数组 - 用 unique_ptr<T[]> 或 vector
总结
- unique_ptr: "这个资源只属于我,我负责释放"
- shared_ptr: "这个资源我们可以共享,最后一个使用者负责释放"
- 根据所有权的需求选择合适的智能指针,能有效避免内存泄漏,使代码更安全清晰。