面试题答案
一键面试设计思路
- RAII原则:利用C++的RAII(Resource Acquisition Is Initialization)机制,确保每个资源在对象生命周期结束时自动释放。在
ResourceManager
类中,每个资源应该由对应的成员对象管理,这些成员对象本身遵循RAII原则。 - 异常安全:析构函数通常不应该抛出异常,因为在栈展开过程中,如果析构函数抛出异常,会导致
std::terminate
被调用。因此,对于可能抛出异常的资源释放操作,需要特殊处理。 - 局部异常处理:在释放网络连接的析构函数中,捕获
std::system_error
异常,确保文件句柄等其他资源正常释放。然后,重新抛出异常,以便上层代码捕获并处理。
关键代码片段
#include <iostream>
#include <stdexcept>
#include <system_error>
#include <memory>
// 模拟文件句柄类
class FileHandle {
public:
FileHandle() { std::cout << "FileHandle created" << std::endl; }
~FileHandle() { std::cout << "FileHandle released" << std::endl; }
};
// 模拟网络连接类
class NetworkConnection {
public:
NetworkConnection() { std::cout << "NetworkConnection created" << std::endl; }
~NetworkConnection() {
std::cout << "NetworkConnection releasing..." << std::endl;
// 模拟可能抛出异常的资源释放操作
throw std::system_error(std::make_error_code(std::errc::network_down), "Network connection error");
}
};
class ResourceManager {
private:
std::unique_ptr<FileHandle> fileHandle;
std::unique_ptr<NetworkConnection> networkConnection;
public:
ResourceManager() : fileHandle(std::make_unique<FileHandle>()), networkConnection(std::make_unique<NetworkConnection>()) {}
~ResourceManager() {
try {
if (networkConnection) {
networkConnection.reset(); // 释放网络连接,可能抛出异常
}
} catch (const std::system_error& e) {
std::cerr << "Caught system_error in NetworkConnection destructor: " << e.what() << std::endl;
// 文件句柄在离开作用域时会自动释放
throw; // 重新抛出异常,让上层代码处理
}
}
};
使用示例
int main() {
try {
ResourceManager manager;
} catch (const std::system_error& e) {
std::cerr << "Caught system_error in main: " << e.what() << std::endl;
}
return 0;
}
在上述代码中:
FileHandle
和NetworkConnection
类分别模拟文件句柄和网络连接资源,它们的析构函数负责释放资源。ResourceManager
类使用std::unique_ptr
来管理FileHandle
和NetworkConnection
对象,确保资源在ResourceManager
对象析构时自动释放。- 在
ResourceManager
的析构函数中,对NetworkConnection
的释放操作进行异常捕获。如果捕获到std::system_error
异常,先确保FileHandle
能正常释放,然后重新抛出异常,以便上层代码处理。 - 在
main
函数中,通过try - catch
块捕获并处理从ResourceManager
析构函数中重新抛出的异常。