news 2026/6/23 11:26:05

【C/C++】RAII,Stack-only对象和Heap-only对象

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【C/C++】RAII,Stack-only对象和Heap-only对象

RAII 详解

什么是 RAII

Resource Acquisition Is Initialization(资源获取即初始化)

核心思想:把资源的生命周期绑定到对象的生命周期

  • 构造函数获取资源
  • 析构函数释放资源
  • 对象销毁时,资源自动释放

FileHandler 示例

没有 RAII 的写法

voidprocess(){FILE*f=fopen("data.txt","r");if(some_error){return;// 忘记 fclose,文件泄漏!}do_something();// 如果抛异常,也泄漏!fclose(f);}

问题:每个退出路径都要手动关闭文件,容易遗漏。

RAII 版本

// 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 已经自动关闭了}}

Stack Only 版本

强制 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,文件永远不会关闭}

Heap Only 版本

有时需要共享文件句柄,使用引用计数:

// 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 │ │ │ └────────────────────────────────────────────────────────┘
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/13 17:38:46

AI智能体改变材料研发:7个案例,架构师的创新思路

AI智能体改变材料研发&#xff1a;7个案例&#xff0c;架构师的创新思路——技术博客文章 下面是根据用户输入的文章主题“AI智能体改变材料研发&#xff1a;7个案例&#xff0c;架构师的创新思路”撰写的一篇技术博客文章。文章采用Markdown格式&#xff0c;内容包括标题选项、…

作者头像 李华
网站建设 2026/6/18 8:49:19

【开题答辩全过程】以 旅游直通车服务为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

作者头像 李华
网站建设 2026/6/10 1:44:44

深度学习网络笔记Ⅴ(Transformer源码详解)

0.前言 基于上一章的学习我们深刻了解了Transformer架构&#xff0c;并也进一步了解到其真实的训练过程。接着进一步我们继续深究Transformer的源码上进行深层次的学习和理解&#xff0c;明白其中的核心内容首先我们需要关注几篇文章和源码。 https://nlp.seas.harvard.edu/ann…

作者头像 李华
网站建设 2026/6/15 17:22:45

魔法打败魔法?这6款超强ai降ai软件,这才是真正的降ai率工具,实测3分钟让文章回归低AI率,安全过检测!

你的论文是不是AI率超高&#xff1f;一查降ai率结果80%以上&#xff1f; 别急&#xff0c;这种情况很多人遇到过。 用AI工具写论文确实快&#xff0c;但“AI味”太浓就容易翻车。 今天我就来分享几款自己用过、真心能打的ai降ai工具&#xff0c;从免费降ai率工具到专业级都涵…

作者头像 李华
网站建设 2026/6/21 21:43:22

基于大数据的咖啡推荐平台的设计与实现

课题背景 随着互联网技术的发展和移动设备的普及&#xff0c;全球咖啡消费市场持续增长&#xff0c;消费者对个性化、精准化的咖啡推荐需求日益强烈。传统的咖啡推荐方式主要依赖人工经验或简单的用户调查&#xff0c;缺乏数据驱动的科学依据&#xff0c;难以满足现代消费者多样…

作者头像 李华
网站建设 2026/6/15 17:35:31

强烈安利!专科生毕业论文必备的9个AI论文网站TOP9测评

强烈安利&#xff01;专科生毕业论文必备的9个AI论文网站TOP9测评 2026年专科生论文写作工具测评&#xff1a;如何选对AI平台提升效率 随着人工智能技术的不断进步&#xff0c;越来越多的专科生开始借助AI工具辅助毕业论文写作。然而&#xff0c;面对市场上琳琅满目的论文辅助网…

作者头像 李华