这又是什么新奇玩意呀?
自定义删除器是智能指针(std::unique_ptr / std::shared_ptr)的一个特性:允许你指定一个函数或函数对象,在智能指针析构时用它来释放资源,而不是默认的 delete。
为什么需要它
默认情况下 unique_ptr<T> 用 delete ptr 释放,unique_ptr<T[]> 用 delete[] ptr。但很多资源的释放方式不是 delete:
-
C 风格 API 分配的内存:
malloc需要free -
文件句柄:
fopen需要fclose -
系统句柄:
CreateFile/socket/HANDLE需要对应的CloseHandle/close -
第三方库对象:需要调用专门的
xxx_destroy()函数
如果你的智能指针管的是你自己写的 class/struct,且它的析构函数已经正确清理了它内部持有的资源 ,那么不需要自定义删除器。
ps:还记的析构函数需要处理哪些资源吗?如果不记得,可以看看这篇文章:c++析构函数应该处理哪些资源
如果你的智能指针管的是"一个裸句柄/裸指针"(比如 FILE*、HANDLE、void*),那这个"被管理的类型"根本没有析构函数 ,就需要自定义删除器。
这种情况在实际开发也许会遇到
下面就以简单的示例代码来说明自定义删除器吧
情况一:不需要自定义删除器
#include <cstdio>
#include <memory>
class FileWrapper {
public:
explicit FileWrapper(const char* path) : fp_(std::fopen(path, "w")) {}
FileWrapper(const FileWrapper&) = delete;
FileWrapper& operator=(const FileWrapper&) = delete;
~FileWrapper() {
if (fp_) std::fclose(fp_); // 析构函数负责关闭
}
std::FILE* get() const { return fp_; }
private:
std::FILE* fp_;
};
int main() {
// 管的是 FileWrapper 对象本身
auto p = std::make_unique<FileWrapper>("a.txt");
// p 析构 -> 调用 ~FileWrapper() -> fclose(fp_)
// 默认删除器 default_delete<FileWrapper> 做的是 delete p.get(),
// 而 delete 会调用 ~FileWrapper(),资源被正确释放
}
情况二:需要自定义删除器
#include <cstdio>
#include <memory>
#include <stdexcept>
#include <windows.h>
class FileHandle {
public:
// 构造:接管一个已打开的 FILE*
explicit FileHandle(std::FILE* f) : fp_(f, &std::fclose) {}
// 取裸句柄,用于调用 C 风格 API(如 fputs / fread)
std::FILE* get() const { return fp_.get(); }
// 是否持有有效句柄
explicit operator bool() const { return fp_ != nullptr; }
// 显式关闭(可选):提前释放资源
void reset() { fp_.reset(); }
// 禁止拷贝(unique_ptr 本身已禁拷贝,这里显式写出更清晰)
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
// 允许移动(unique_ptr 支持移动,编译器会隐式生成)
FileHandle(FileHandle&&) noexcept = default;
FileHandle& operator=(FileHandle&&) noexcept = default;
private:
// 核心:unique_ptr 持有 FILE*,删除器是 fclose
std::unique_ptr<std::FILE, decltype(&std::fclose)> fp_;
};
int main() {
// 设置控制台输出编码为 UTF-8
SetConsoleOutputCP(65001);
// 1) 打开文件并交给 FileHandle 管理
std::FILE* raw = std::fopen("demo.txt", "w");
if (!raw) {
std::perror("fopen");
return 1;
}
FileHandle fh(raw);
if (!fh) {
std::fprintf(stderr, "文件句柄无效\n");
return 1;
}
// 2) 使用:通过 get() 拿裸指针调用 C API
std::fputs("hello, FileHandle\n", fh.get());
std::fputs("second line\n", fh.get());
std::printf("写入完成,句柄地址 = %p\n", static_cast<void*>(fh.get()));
// 3) 离开作用域时,fh 析构 -> fp_ 析构 -> 自动调用 fclose
// 无需手动 fclose
std::printf("--- 即将离开作用域,自动 fclose ---\n");
return 0;
}
运行结果
入完成,句柄地址 = 000001b8ec3f45c0
--- 即将离开作用域,自动 fclose ---
写入的demo.txt文件内容如下
hello, FileHandle
second line
下一篇:c++析构函数应该处理哪些资源
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/qq_40698103/article/details/170608744



