【C++系列】智能指针自定义析构
在 C++ 中,智能指针(如 std::unique_ptr
和 std::shared_ptr
)允许自定义析构函数(称为 deleter),用于在释放资源时执行特定操作。
1. std::unique_ptr
自定义析构函数
原理
std::unique_ptr
的模板包含两个参数:
template<class T, class Deleter = std::default_delete<T>>
class unique_ptr;
-
Deleter
类型:可调用对象(函数、Lambda、函数对象),接收T*
参数。
- 示例 1:使用函数作为删除器
#include <iostream>
#include <memory>// 自定义删除函数
void FileDeleter(FILE* file) {if (file) {std::cout << "Closing file\n";fclose(file); // 关闭文件}
}int main() {// 自定义删除器类型: decltype(&FileDeleter)std::unique_ptr<FILE, decltype(&FileDeleter)> file(fopen("test.txt", "w"), FileDeleter // 传入删除器函数);// 当 file 超出作用域时,自动调用 FileDeleter
}
-
示例 2:使用 Lambda 作为删除器
auto deleter = [](FILE* f) {std::cout << "Lambda closes file\n";if (f) fclose(f);
};int main() {// decltype(deleter) 获取 Lambda 类型std::unique_ptr<FILE, decltype(deleter)> file(fopen("test.txt", "w"), deleter // 传入 Lambda);
}
-
示例 3:使用函数对象(仿函数)
struct FileDeleter {void operator()(FILE* f) const {std::cout << "Functor closes file\n";if (f) fclose(f);}
};int main() {// 指定删除器类型 FileDeleterstd::unique_ptr<FILE, FileDeleter> file(fopen("test.txt", "w")// 构造时可不显式传递,默认构造删除器对象);
}
2. std::shared_ptr
自定义析构函数
原理
std::shared_ptr
的删除器通过构造函数传入,不影响类型,因此更灵活:
template<class Y, class Deleter>
shared_ptr(Y* ptr, Deleter d);
示例:管理动态数组
#include <iostream>
#include <memory>int main() {// 删除器:用 delete[] 释放数组auto deleter = [](int* p) {std::cout << "Deleting array\n";delete[] p;};// 共享指针管理数组std::shared_ptr<int> arr(new int[10], deleter);// 等效写法:直接用 unique_ptr 管理数组// std::unique_ptr<int[]> arr(new int[10]); // 内置数组支持
}
常见应用场景
-
文件句柄
std::unique_ptr<FILE, decltype(&fclose)> file(fopen("a.txt", "r"), fclose);
- 动态数组(需手动释放)
std::shared_ptr<int> arr(new int[10], [](int* p) { delete[] p; });
- 互斥锁(自动解锁)
std::unique_ptr<std::mutex, std::function<void(std::mutex*)>> lockPtr(&mtx, [](std::mutex* m) { m->unlock(); });
- C 资源(如 OpenSSL 对象)
std::unique_ptr<BIO, decltype(&BIO_free)> bio(BIO_new(...), BIO_free);
关键注意事项
-
unique_ptr
的删除器是类型的一部分- 不同删除器的
unique_ptr
属于不同类型。 - 例如:
unique_ptr<int, DeleterA>
和unique_ptr<int, DeleterB>
不兼容。
- 不同删除器的
-
shared_ptr
的删除器不影响类型- 所有
shared_ptr<T>
无论删除器如何,类型相同。 - 删除器存储在控制块中,动态调用。
- 所有
-
空指针与删除器
删除器需处理指针为空的情况。 -
性能影响
unique_ptr
的删除器通常无额外开销(可内联)。shared_ptr
的删除器存储在堆上,略有开销。