unique_ptr
基本概念
std::unique_ptr<T> 是独占式智能指针:
- 独占对象所有权,不可拷贝;
- 可移动(C++11);
- 离开作用域时自动删除所管理对象;
- 指针唯一,适合资源严格独占场景。
底层原理
特性:
- 内部只有一个裸指针
T* ptr; - 不需要引用计数
- 拥有者离开作用域时调用
delete或自定义 deleter
结构示意:
cpp
template<class T, class Deleter = std::default_delete<T>>
class unique_ptr {
private:
T* ptr;
Deleter del;
};
删除动作:
cpp
~unique_ptr() {
if (ptr) del(ptr);
}
典型用法
-
创建
auto p = std::make_unique<int>(10);
-
移动所有权
std::unique_ptr<int> p1 = std::make_unique<int>(5);
std::unique_ptr<int> p2 = std::move(p1); -
自定义删除器
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("a.txt","r"), &fclose);
使用场景
std::unique_ptr 的核心是 独占所有权,适合代表"资源严格只有一个拥有者"的场景。
只要不是多个对象共享所有权,就应该优先使用 unique_ptr。
它是默认、最安全、性能最佳的智能指针。
示例:unique_ptr 用法
cpp
#include <iostream>
#include <memory>
struct Foo {
Foo() { std::cout << "Foo()\n"; }
~Foo() { std::cout << "~Foo()\n"; }
};
int main() {
std::unique_ptr<Foo> p1 = std::make_unique<Foo>();
// 转移所有权
std::unique_ptr<Foo> p2 = std::move(p1);
if (!p1) std::cout << "p1 is null\n";
}
输出:
Foo()
p1 is null
~Foo()
shared_ptr
基本概念
std::shared_ptr<T> 是共享所有权智能指针:
- 多个 smart pointer 可指向同一对象;
- 使用引用计数计管理资源生命周期;
- 最后一个
shared_ptr消失时才释放资源。
底层原理
数据结构
shared_ptr 中含有两个关键对象:
- 控制块(control block) 包含:
use_count(引用计数)weak_count- 删除器 Deleter
- 分配器 Allocator
- 指向对象的指针
- shared_ptr 内部只有两个指针
cpp
T* ptr; // 指向对象
ControlBlock* ctrl; // 指向控制块
创建方式
推荐:make_shared
cpp
auto p = std::make_shared<int>(10);
优点:
- 对象和控制块在同一块内存
- 更少的内存分配
- 更高的缓存局部性
- 更安全(异常安全)
拷贝/赋值:引用计数 +1
cpp
auto a = std::make_shared<int>(5);
auto b = a; // use_count = 2
离开作用域:引用计数 -1
引用计数变为 0 时执行删除器:
cpp
~shared_ptr() {
if (--ctrl->use_count == 0) {
del(ptr);
}
}
示例:shared_ptr 引用计数演示
cpp
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> p1 = std::make_shared<int>(42);
std::cout << p1.use_count() << "\n"; // 1
{
std::shared_ptr<int> p2 = p1;
std::cout << p1.use_count() << "\n"; // 2
}
std::cout << p1.use_count() << "\n"; // 1
}
unique_ptr VS shared_ptr
| 特性 | unique_ptr | shared_ptr |
|---|---|---|
| 所有权 | 独占 | 共享 |
| 拷贝 | 不可 | 可 |
| 移动 | 可 | 可 |
| 内存开销 | 小(仅一个指针) | 大(含控制块) |
| 生命周期 | 自动,但唯一 | 引用计数控制 |
| 性能 | 更快 | 较慢(原子操作) |
| 适用场景 | 独占资源 | 多模块共享资源 |