讲师中心 微信公众号

工具推荐

视频效率加速
Seko
Seko

AI短剧一键生成成片

updream

一键生成高质量推广成片

AniShort
AniShort

AI短剧协同制作平台

剧云
剧云

中文短剧剧本制作平台

C++如何实现对象的延迟析构?(RAII延迟释放模式)

小雪同学_6598

小雪同学_6598

发布时间:2026-02-20 10:34:03

|

754人浏览过

|

来源于php中文网

原创

延迟析构的核心是解耦“逻辑销毁”与“物理释放”,防止UAF:通过shared_ptr自定义deleter、atomic标记或weak_ptr边界检查实现,关键在确保释放时机安全可控。

c++如何实现对象的延迟析构?(raii延迟释放模式)

为什么不能直接 delete 对象后还访问它

延迟析构不是“不让析构”,而是让析构时机可控——比如对象还在被其他线程读取,或正处在回调链中,此时强行 delete 会触发 UAF(Use-After-Free)。RAII 本身不提供延迟能力,std::unique_ptr 和 std::shared_ptr 的析构都是即时的,除非你主动把释放逻辑抽出来。

std::shared_ptr 配合自定义 deleter 实现延迟执行

这是最轻量、无需额外锁、且符合 RAII 直觉的做法:引用计数归零时并不立即释放资源,而是把释放动作交给一个可延后调用的函数(比如投递到线程池、压入队列、或等下一个事件循环 tick)。

常见错误是把 deleter 写成捕获局部变量的 lambda,导致 dangling reference:

auto ptr = std::shared_ptr<MyObj>(new MyObj, [](MyObj* p) {
    // ❌ 错误:如果 this_queue 是栈变量,这里已析构
    this_queue->post([p]{ delete p; }); 
});

正确做法是确保 deleter 捕获的都是生命周期足够长的对象(如全局队列、静态线程池),或用 std::weak_ptr 避免强引用循环:

立即学习“C++免费学习笔记(深入)”;

  • deleter 中只做「调度」,不直接操作被管理对象的成员
  • 如果需访问对象状态,先用 std::shared_ptr 重新构造(但要确认此时是否仍安全)
  • 避免在 deleter 里抛异常;C++ 标准规定若 delete 抛异常,程序直接 terminate

手动管理 + std::atomic<bool></bool> 标记延迟释放条件

适合对性能敏感、且释放逻辑简单(比如仅需 delete)的场景。核心是把“析构权”和“对象存活权”解耦:对象内存仍存在,但业务逻辑认为它已“逻辑销毁”。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

典型结构:

  • 对象内含 std::atomic<bool> m_released{false}</bool>
  • 所有公开方法开头加 if (m_released.load(std::memory_order_acquire)) return;
  • 销毁入口(如 close())设为 true,并触发异步清理任务
  • 清理任务中检查 m_released 并真正 delete this(注意:只能用于 new 分配的、非栈对象)

容易踩的坑:

  • 忘记在 delete this 前调用基类析构逻辑(如有虚函数,必须显式调用 ~Base())
  • std::memory_order 选错:release 写要用 memory_order_release,读端对应 memory_order_acquire
  • 多线程下,对象可能被多个地方同时标记 released,delete this 只能执行一次

用 std::weak_ptr 触发延迟析构的边界检查

当延迟析构需要“等待所有观察者离开”时,std::weak_ptr 是天然的信号源。比如一个对象被多个 worker 持有 std::weak_ptr,只有全部失效后才真正释放。

关键点:

  • 持有方必须用 lock() 转成 std::shared_ptr 才能安全访问;返回空说明对象已不可达
  • 不能靠 use_count() 判断——它不包含 weak_ptr 数量,且多线程下瞬时值无意义
  • 想实现“最后一个 weak_ptr 析构时触发清理”,得配合 std::enable_shared_from_this + 自定义控制块(较重,一般不推荐)

更实用的做法是:主线程维护一个 std::vector<:weak_ptr>></:weak_ptr>,定期遍历 lock(),清掉空项;当 vector 为空,再 delete 底层对象。

真正难的不是怎么写延迟逻辑,而是判断“什么时候才算安全释放”——这往往取决于你的并发模型和对象职责。比如网络连接对象,可能要等发送缓冲区清空、IOCP 完成例程返回、且所有 callback 已出栈,才能算真正可删。这些条件不会自动聚合,得靠你用状态机或引用计数显式建模。

热门AI工具

更多
VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

花生AI
花生AI Hot

一款AI视频创作工具,主要用于B站推出的AI视频创作工具,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

1171

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

345

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

674

2026.01.05

C++ Lambda 表达式与函数式编程
C++ Lambda 表达式与函数式编程

深入讲解 C++ Lambda 表达式与函数式编程范式,涵盖 Lambda 基础语法与返回值推导、值捕获与引用捕获的区别与陷阱、初始化捕获(C++14 广义捕获)、泛型 Lambda(auto 参数)、mutable 关键字修改捕获变量、std::function 类型擦除与函数包装、std::bind 参数绑定(及其被 Lambda 替代的趋势)、Lambda 在 STL 算法(sort/transform/for_each/remo

849

2026.05.06

Java 函数式接口与 Lambda 进阶技巧
Java 函数式接口与 Lambda 进阶技巧

在 Java Stream 基础之上进一步深入函数式编程,涵盖 @FunctionalInterface 注解与自定义函数式接口设计、四种方法引用(静态/实例/对象/构造器)的使用场景、Lambda 中的 effectively final 变量捕获规则、函数组合(andThen/compose)与柯里化技巧、Comparator 链式比较器构建、CompletableFuture 异步函数式编排、Reactor / RxJava 响应

448

2026.05.08

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

7027

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2888

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4878

2023.08.10

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

40

2026.11.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn