4.1. 智能指针
4.1.1. unique_ptr
std::unique_ptr 表示独占所有权,是最常用的智能指针。
#include <memory>
// 创建
auto ptr = std::make_unique<int>(42); // C++14 推荐
std::unique_ptr<int> ptr2(new int(42)); // 也可以
// 使用
std::cout << *ptr << "\n"; // 42
// 移动所有权
auto ptr3 = std::move(ptr); // ptr 变为 nullptr
// 释放并获取原始指针
int* raw = ptr3.release();
delete raw;
// 重置
ptr3.reset(new int(100)); // 释放旧对象,管理新对象
ptr3.reset(); // 释放并置空
4.1.1.1. 数组支持
// 管理数组
auto arr = std::make_unique<int[]>(100);
arr[0] = 42;
// 自定义删除器
auto file_ptr = std::unique_ptr<FILE, decltype(&fclose)>(
fopen("file.txt", "r"),
&fclose
);
4.1.1.2. 函数参数传递
// 转移所有权:按值传递 unique_ptr
void take_ownership(std::unique_ptr<Widget> widget) {
// 函数拥有 widget
}
auto w = std::make_unique<Widget>();
take_ownership(std::move(w)); // 必须显式 move
// 不转移所有权:传递引用或原始指针
void use_widget(const Widget& widget); // 只读
void use_widget(Widget& widget); // 可修改
void use_widget(Widget* widget); // 可选参数(可为 null)
4.1.3. weak_ptr
std::weak_ptr 是对 shared_ptr 管理对象的弱引用,不增加引用计数。
std::shared_ptr<int> sp = std::make_shared<int>(42);
std::weak_ptr<int> wp = sp;
std::cout << wp.use_count(); // 1(不增加)
// 检查对象是否存在
if (!wp.expired()) {
// 对象可能在下一刻被销毁
}
// 安全访问:提升为 shared_ptr
if (auto locked = wp.lock()) {
std::cout << *locked;
}
// 对象销毁后
sp.reset();
std::cout << wp.expired(); // true
auto locked = wp.lock(); // 返回空 shared_ptr
4.1.3.1. 用途:缓存
class ResourceCache {
std::unordered_map<std::string, std::weak_ptr<Resource>> cache_;
public:
std::shared_ptr<Resource> get(const std::string& key) {
auto it = cache_.find(key);
if (it != cache_.end()) {
if (auto sp = it->second.lock()) {
return sp; // 缓存命中
}
cache_.erase(it); // 清理过期条目
}
auto resource = std::make_shared<Resource>(key);
cache_[key] = resource;
return resource;
}
};
4.1.5. 性能考虑
4.1.5.1. shared_ptr 开销
// shared_ptr 开销
// - 两个指针(对象 + 控制块)
// - 引用计数原子操作
// 在性能关键路径避免频繁拷贝
void process(const std::shared_ptr<Data>& data); // 传引用
void process(Data* data); // 或传原始指针
// 不要这样
void process(std::shared_ptr<Data> data); // 拷贝增加引用计数
4.1.5.2. unique_ptr 开销
// unique_ptr 通常与原始指针大小相同
static_assert(sizeof(std::unique_ptr<int>) == sizeof(int*));
// 除非使用非空删除器
auto up = std::unique_ptr<int, void(*)(int*)>(
new int, [](int* p) { delete p; }
);
// 需要存储函数指针,更大
4.1.6. 智能指针选择指南
// 默认选择:unique_ptr
auto widget = std::make_unique<Widget>();
// 需要共享时:shared_ptr
auto shared = std::make_shared<Widget>();
// 打破循环/观察者:weak_ptr
std::weak_ptr<Widget> observer = shared;
// 与 C API 交互:原始指针
void c_api(Widget* ptr);
c_api(widget.get());
小技巧
智能指针使用原则:
优先使用
unique_ptr只在需要共享所有权时使用
shared_ptr使用
weak_ptr打破循环引用使用
make_unique和make_shared传参时优先传引用或原始指针