一、std::make_unique 完整创建流程拆解
cpp
运行
auto task = std::make_unique<AudioTask>();
1. 底层动作分步
- 堆内存分配 在堆上开辟一块足够存放
AudioTask结构体大小的内存; - 就地构造对象 调用
AudioTask的无参默认构造函数,初始化堆里的实例; - 生成
std::unique_ptr<AudioTask>独占智能指针对象 这个智能指针存放在当前函数栈 (局部变量task); - 绑定所有权
task是唯一拥有释放权限 的持有者,任何时候只有它能负责delete这块堆内存。
2. 等价裸指针对照(帮你看透底层)
cpp
运行
// make_unique 等价手写裸指针版本
AudioTask* raw = new AudioTask();
std::unique_ptr<AudioTask> task(raw);
区别:
make_unique更安全:不会出现new成功、unique_ptr构造抛异常导致内存泄漏的边界问题;- 代码更简洁,不用重复写类型
AudioTask。
3. 带参数构造的扩展写法
如果你的 AudioTask 有自定义构造函数:
cpp
运行
struct AudioTask {
AudioTask(AudioTaskType t) : type(t) {}
AudioTaskType type;
std::vector<int16_t> pcm;
};
// 传参构造,参数直接转发给类构造函数
auto task = std::make_unique<AudioTask>(kAudioTaskTypeEncodeToSendQueue);
二、auto 类型推导
auto task 最终推导出来的真实类型:
cpp
运行
std::unique_ptr<AudioTask> task = std::make_unique<AudioTask>();
auto 自动匹配返回值类型,不用手写一长串模板。
三、创建后所有权关键特性
- 禁止拷贝
unique_ptr删除了拷贝构造 / 拷贝赋值,下面代码直接编译报错:
cpp
运行
auto task2 = task; // 错误!独占指针不能复制,会破坏唯一所有权
- 只允许移动转移所有权 只能用
std::move移交掌控权,移交后原指针变空:
cpp
运行
audio_encode_queue_.push_back(std::move(task));
// 此时 task == nullptr,不再持有堆对象
// 队列里的unique_ptr成为新唯一持有者
四、RAII 自动销毁逻辑
局部变量 task 是栈上对象:
- 正常函数结束、代码块闭合 →
task栈变量自动析构; unique_ptr析构函数内部自动执行delete,释放堆上AudioTask;AudioTask内部成员std::vector<int16_t> pcm会跟着结构体析构,同步释放 PCM 采样的堆缓冲区;全程无内存泄漏,不用手动delete。
五、对比另一种创建方式(不推荐)
cpp
运行
// 不推荐写法,风险更高
std::unique_ptr<AudioTask> task(new AudioTask());
- 功能一致,但异常安全弱于
make_unique;工程标准写法一律优先std::make_unique。