题目
智能指针与资源管理
信息
- 类型:问答
- 难度:⭐⭐
考点
智能指针的使用,移动语义,自定义删除器
快速回答
在C++11及以上版本中,智能指针是管理动态内存的核心工具:
- 优先使用
std::unique_ptr实现独占所有权资源管理 - 需要共享所有权时使用
std::shared_ptr并注意循环引用问题 - 通过移动语义(
std::move)转移unique_ptr所有权 - 对非内存资源(如文件句柄)使用自定义删除器
问题场景
假设需要实现一个FileHandler类,封装文件操作并满足:
- 文件资源在对象销毁时自动关闭
- 支持所有权的安全转移
- 避免资源泄漏和重复释放
原理说明
C++11引入的智能指针通过RAII(资源获取即初始化)机制自动管理资源:
- std::unique_ptr:独占所有权,不可复制但可移动
- std::shared_ptr:共享所有权,基于引用计数
- 自定义删除器:允许指定资源释放逻辑(如
fclose)
代码实现
#include <memory>
#include <cstdio>
class FileHandler {
public:
// 自定义删除器
struct FileDeleter {
void operator()(FILE* fp) const {
if(fp) {
std::fclose(fp);
std::cout << "File closed\n";
}
}
};
// 使用 unique_ptr 管理文件资源
using UniqueFilePtr = std::unique_ptr<FILE, FileDeleter>;
explicit FileHandler(const char* filename, const char* mode)
: file_(std::fopen(filename, mode)) {
if(!file_) throw std::runtime_error("File open failed");
}
// 支持移动语义
FileHandler(FileHandler&&) = default;
FileHandler& operator=(FileHandler&&) = default;
void write(const char* data) {
if(std::fputs(data, file_.get()) == EOF)
throw std::runtime_error("Write error");
}
private:
UniqueFilePtr file_;
};
// 使用示例
int main() {
FileHandler f1("test.txt", "w");
f1.write("Hello ");
// 所有权转移
FileHandler f2 = std::move(f1);
f2.write("World!");
return 0;
} // 文件自动关闭最佳实践
- 首选unique_ptr:默认使用独占所有权,避免引用计数开销
- 移动而非复制:通过
std::move转移资源所有权 - 自定义删除器:管理非内存资源(文件/网络套接字等)
- 避免裸指针:不调用
get()获取底层指针除非必要
常见错误
| 错误示例 | 后果 | 修正方案 |
|---|---|---|
std::unique_ptr<FILE> ptr(fopen(...)); | 未调用fclose导致资源泄漏 | 添加自定义删除器 |
FileHandler f3 = f2; | 编译错误(复制被禁用) | 使用std::move |
fclose(file_.get()); | 导致重复释放 | 依赖RAII自动管理 |
扩展知识
- std::shared_ptr:当需要共享所有权时使用,注意用
std::make_shared创建 - std::weak_ptr:解决
shared_ptr循环引用问题 - enable_shared_from_this:在类内部获取自身的
shared_ptr - C++17新增的
std::unique_ptr<T[]>支持数组类型