文档解析API哪个好用
2026/1/7 22:29:46
Resource Acquisition Is Initialization(资源获取即初始化)
核心思想:把资源的生命周期绑定到对象的生命周期
voidprocess(){FILE*f=fopen("data.txt","r");if(some_error){return;// 忘记 fclose,文件泄漏!}do_something();// 如果抛异常,也泄漏!fclose(f);}问题:每个退出路径都要手动关闭文件,容易遗漏。
// file_handler.hpp#pragmaonce#include<cstdio>#include<stdexcept>#include<string>classFileHandler{FILE*fp;public:// 构造时打开文件(获取资源)FileHandler(constchar*path,constchar*mode):fp(fopen(path,mode)){if(!fp){throwstd::runtime_error("Cannot open file: "+std::string(path));}}// 析构时关闭文件(释放资源)~FileHandler(){if(fp){fclose(fp);}}// 禁止拷贝(避免双重关闭)FileHandler(constFileHandler&)=delete;FileHandler&operator=(constFileHandler&)=delete;// 允许移动FileHandler(FileHandler&&other)noexcept:fp(other.fp){other.fp=nullptr;}FileHandler&operator=(FileHandler&&other)noexcept{if(this!=&other){if(fp)fclose(fp);fp=other.fp;other.fp=nullptr;}return*this;}// 使用文件FILE*get()const{returnfp;}size_tread(void*buf,size_t size){returnfread(buf,1,size,fp);}size_twrite(constvoid*buf,size_t size){returnfwrite(buf,1,size,fp);}};#include"file_handler.hpp"#include<iostream>voidprocess(){FileHandlerfile("data.txt","r");// 打开文件if(some_error){return;// 自动关闭!}do_something();// 异常也自动关闭!charbuf[1024];file.read(buf,sizeof(buf));}// 离开作用域,自动关闭intmain(){try{FileHandlerf1("input.txt","r");FileHandlerf2("output.txt","w");charbuf[4096];size_t n;while((n=f1.read(buf,sizeof(buf)))>0){f2.write(buf,n);}}catch(conststd::exception&e){std::cerr<<e.what()<<"\n";// f1, f2 已经自动关闭了}}强制 FileHandler 只能在栈上创建,确保 RAII 生效:
// file_handler_stack.hpp#pragmaonce#include<cstdio>#include<stdexcept>classFileHandler{FILE*fp;public:FileHandler(constchar*path,constchar*mode):fp(fopen(path,mode)){if(!fp)throwstd::runtime_error("Cannot open file");}~FileHandler(){if(fp)fclose(fp);}// 禁止拷贝FileHandler(constFileHandler&)=delete;FileHandler&operator=(constFileHandler&)=delete;// 禁止堆分配,强制栈上使用void*operatornew(size_t)=delete;void*operatornew[](size_t)=delete;FILE*get()const{returnfp;}};使用:
voidprocess(){FileHandlerfile("data.txt","r");// ✓ 栈上,自动管理// FileHandler* p = new FileHandler(); // ✗ 编译错误}为什么要 Stack Only?防止这种情况:
voidbad(){FileHandler*p=newFileHandler("data.txt","r");// 忘记 delete p,文件永远不会关闭}有时需要共享文件句柄,使用引用计数:
// file_handler_heap.hpp#pragmaonce#include<cstdio>#include<memory>#include<stdexcept>classFileHandler{FILE*fp;// 私有构造/析构,只能通过 create() 创建FileHandler(constchar*path,constchar*mode):fp(fopen(path,mode)){if(!fp)throwstd::runtime_error("Cannot open file");}~FileHandler(){if(fp)fclose(fp);}public:// 工厂方法,返回 shared_ptrstaticstd::shared_ptr<FileHandler>create(constchar*path,constchar*mode){autop=newFileHandler(path,mode);// lambda 在成员函数内,可以访问私有析构returnstd::shared_ptr<FileHandler>(p,[](FileHandler*f){deletef;});}FILE*get()const{returnfp;}};使用:
voidprocess(){// FileHandler f("data.txt", "r"); // ✗ 编译错误autofile=FileHandler::create("data.txt","r");// ✓autofile2=file;// 共享所有权,引用计数 = 2// 传给其他函数/线程async_read(file);}// 引用计数归零时自动关闭┌─────────────────┬──────────────────┬──────────────────┬──────────────────┐ │ │ 普通 RAII │ Stack Only │ Heap Only │ ├─────────────────┼──────────────────┼──────────────────┼──────────────────┤ │ 栈上创建 │ ✓ │ ✓ │ ✗ │ ├─────────────────┼──────────────────┼──────────────────┼──────────────────┤ │ 堆上创建 │ ✓ │ ✗ │ ✓ │ ├─────────────────┼──────────────────┼──────────────────┼──────────────────┤ │ 生命周期 │ 作用域或手动 │ 作用域 │ 引用计数 │ ├─────────────────┼──────────────────┼──────────────────┼──────────────────┤ │ 共享所有权 │ 需要 shared_ptr │ ✗ │ ✓ (内置) │ ├─────────────────┼──────────────────┼──────────────────┼──────────────────┤ │ 适用场景 │ 通用 │ 局部资源管理 │ 跨作用域/线程共享 │ └─────────────────┴──────────────────┴──────────────────┴──────────────────┘┌────────────────────────────────────────────────────────┐ │ RAII 核心 │ ├────────────────────────────────────────────────────────┤ │ │ │ 构造 = 获取资源 │ │ 析构 = 释放资源 │ │ 对象死亡 = 资源释放 │ │ │ ├────────────────────────────────────────────────────────┤ │ 好处 │ ├────────────────────────────────────────────────────────┤ │ │ │ • 不会忘记释放 │ │ • 异常安全 │ │ • 代码简洁 │ │ │ ├────────────────────────────────────────────────────────┤ │ 选择指南 │ ├────────────────────────────────────────────────────────┤ │ │ │ 局部使用 → Stack Only │ │ 需要共享 → Heap Only + shared_ptr │ │ 不确定 → 普通 RAII │ │ │ └────────────────────────────────────────────────────────┘