面试题答案
一键面试场景描述
假设我们要在C++ 中使用文件描述符进行文件操作,并且希望使用std::unique_ptr
来管理这个文件描述符,以确保文件描述符在不再需要时能被正确关闭。在Unix - like系统中,文件描述符是一个整数类型,通过open
函数打开文件会返回一个文件描述符,使用完后需要通过close
函数关闭。
自定义删除器设计思路
- 明确功能:自定义删除器的主要功能是在
std::unique_ptr
销毁其所管理的资源(文件描述符)时,调用合适的函数(如close
)来释放该资源。 - 参数设计:删除器函数需要接收文件描述符作为参数,以便进行关闭操作。
实现细节
#include <iostream>
#include <memory>
#include <unistd.h> // 包含close函数
// 自定义删除器
struct FileDescriptorDeleter {
void operator()(int* fd) const {
if (fd != nullptr) {
close(*fd);
delete fd;
}
}
};
int main() {
// 打开文件获取文件描述符
int* fileDescriptor = new int(open("test.txt", O_RDONLY));
if (*fileDescriptor == -1) {
std::cerr << "Failed to open file" << std::endl;
return 1;
}
// 使用std::unique_ptr管理文件描述符,并传入自定义删除器
std::unique_ptr<int, FileDescriptorDeleter> filePtr(fileDescriptor);
// 这里可以进行文件操作,例如读取文件内容
// 当filePtr超出作用域时,自定义删除器会自动调用close关闭文件描述符
return 0;
}
在上述代码中:
- 定义了
FileDescriptorDeleter
结构体,它重载了()
运算符,实现了删除逻辑。在operator()
中,首先检查文件描述符指针是否为空,不为空则调用close
关闭文件描述符,并释放内存。 - 在
main
函数中,通过open
函数获取文件描述符,并使用new
分配了一个指向该文件描述符的指针。然后使用std::unique_ptr
来管理这个指针,并传入自定义删除器FileDescriptorDeleter
。
必要性和优势
- 必要性:
- 异常安全:如果在使用文件描述符的过程中发生异常,手动调用
close
函数可能会被跳过,导致文件描述符未关闭,产生资源泄漏。而std::unique_ptr
结合自定义删除器可以确保无论是否发生异常,文件描述符都会被正确关闭。 - 遵循RAII原则:RAII(Resource Acquisition Is Initialization)原则要求资源的获取和释放应与对象的生命周期绑定。
std::unique_ptr
和自定义删除器正是这种原则的体现,将文件描述符的关闭操作与std::unique_ptr
对象的析构绑定在一起。
- 异常安全:如果在使用文件描述符的过程中发生异常,手动调用
- 优势:
- 简洁清晰:代码结构更加简洁,将资源管理逻辑封装在
std::unique_ptr
和自定义删除器中,使得业务代码更加专注于文件操作本身,而不必担心资源释放的细节。 - 可移植性:通过自定义删除器,可以将特定平台的资源管理函数(如
close
)封装起来,使代码在不同平台上具有更好的可移植性,同时也便于维护和修改资源管理逻辑。
- 简洁清晰:代码结构更加简洁,将资源管理逻辑封装在