c++中的std::unique_ptr的deleter怎么自定义_c++智能指针高级用法【技巧】

自定义 std::unique_ptr 的 deleter 是让指针释放时执行指定逻辑而非仅 delete;支持函数指针、lambda、functor 等可调用类型,需在模板参数中显式声明 deleter 类型。

自定义 std::unique_ptr 的 deleter,核心是让指针在释放资源时执行你指定的逻辑,不只是简单调用 delete

deleter 的类型和写法

deleter 可以是函数指针、函数对象(functor)、lambda 表达式,或任何可调用类型,只要它接受一个参数(指针类型)且无返回值。

  • 函数指针:需提前声明函数,签名形如 void my_deleter(int* p)
  • lambda:最常用,捕获灵活,适合带状态的清理逻辑(比如记录日志、关闭句柄)
  • functor:适合复用、需保存内部状态的场景(如计数器、资源池管理)

基本用法:模板参数显式指定 deleter 类型

必须在 unique_ptr 模板中声明 deleter 类型,否则编译失败:

auto del = [](int* p) { 
    std::cout << "Deleting: " << *p << "\n"; 
    delete p; 
};
std::unique_ptr ptr(new int(42), del);

注意:不能只写 std::unique_ptr 然后传 lambda 构造——类型不匹配。必须把 decltype(del) 显式作为第二个模板参数。

避免手动写 decltype:用 make_unique 的替代方案

C++14 起没有直接支持自定义 deleter 的 make_unique,但可以封装辅助函数:

template 
auto make_unique_with_deleter(Deleter&& d) {
    return std::unique_ptr>(
        new T(), std::forward(d)
    );
}
// 使用
auto ptr = make_unique_with_deleter([](int* p) { delete p; });

这样就不需要反复写 decltype,也避免了类型推导错误。

常见实用场景

  • 释放 C 风格资源:如 fopen / fclose,用 std::unique_ptr
  • 数组管理:用 std::default_delete 替代默认的 delete(防止未定义行为)
  • 共享所有权模拟:deleter 中调用 release() 或触发回调,实现“最后释放时才真正销毁”
  • 调试追踪:deleter 打印地址、计数、校验资源状态,排查泄漏或重复释放

基本上就这些。关键不是“怎么写”,而是想清楚:资源谁分配、谁释放、释放时要做什么——deleter 就是你掌控释放环节的钩子。