c++怎么解决循环引用问题_c++ weak_ptr与shared_ptr配合使用【方法】

发布时间 - 2025-12-27 00:00:00    点击率:
shared_ptr循环引用会导致内存泄漏,需用weak_ptr打破引用链;weak_ptr不增加引用计数,访问前须调用lock()获取临时shared_ptr,且应避免滥用以规避设计缺陷。

shared_ptr 循环引用会导致内存泄漏

当两个对象用 shared_ptr 互相持有对方时,引用计数永远无法归零,析构函数不会被调用,内存就一直卡着不释放。这不是“程序崩溃”,而是静默的资源泄露——跑得越久,占用越多。

用 weak_ptr 打破循环中的一个引用链

weak_ptr 不增加引用计数,只“观察”所指向的 shared_ptr 是否还有效。它本身不参与所有权管理,因此不会延长对象生命周期。

典型做法是:一方用 shared_ptr 持有另一方,另一方用 weak_ptr 回指——比如父类持子类的 shared_ptr,子类用 weak_ptr 指向父类。

  • 必须在访问前调用 lock() 转成临时 shared_ptr,否则可能访问已销毁对象
  • weak_ptr 不能直接解引用,也不能参与构造/赋值 shared_ptr
  • 不要长期保存 weak_ptr::lock() 返回的 shared_ptr,除非你真需要延长其生命周期

实际代码中怎么写才安全

下面是一个父子结构的最小可运行示例,展示如何避免循环引用:

#include 
#include 

struct Child;
struct Parent {
    std::shared_ptr child;
    ~Parent() { std::cout << "Parent destroyed\n"; }
};

struct Child {
    std::weak_ptr parent; // 注意:不是 shared_ptr
    ~Child() { std::cout << "Child destroyed\n"; }
};

int main() {
    auto p = std::make_shared();
    auto c = std::make_shared();
    p->child = c;
    c->parent = p; // 只是观察,不增加引用计数

    // 安全访问父对象
    if (auto locked_parent = c->parent.lock()) {
        std::cout << "Parent still alive\n";
    } else {
        std::cout << "Parent already gone\n";
    }
} // 输出:Child destroyed → Parent destroyed(顺序取决于析构时机)

weak_ptr 不是万能的,别滥用

weak_ptr 解决的是“谁该拥有谁”的设计问题,不是补丁工具。如果发现要到处加 weak_ptr,大概率是类职责或生命周期设计不合理。

常见误用包括:

  • weak_ptr 当成“可空指针”替代 shared_ptr 或裸指针——它开销更大,且每次访问都要 lock()
  • 在回调、信号槽等跨线程场景中没考虑 weak_ptr::lock() 的线程安全性(它是线程安全的,但后续使用仍需同步)
  • 忘记检查 lock() 返回是否为空,直接解引用导致未定义行为

真正关键的,是画清楚对象图、标出所有权方向,再决定哪里该用 shared_ptr、哪里该用 weak_ptr,或者干脆换用裸指针 + 明确生命周期约束。


# go  # 工具  # ai  # c++  # ios  # stream  # red  # 父类  # 子类  # 析构函数  # 循环  # 指针  # 线程  # 空指针  # 对象  # 该用  # 的是  # 是一个  # 都要  # 更大  # 它是  # 你真  # 这不是  # 越多 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何在建站宝盒中设置产品搜索功能?  nodejs redis 发布订阅机制封装实现方法及实例代码  如何快速上传建站程序避免常见错误?  html5audio标签播放结束怎么触发事件_onended回调方法【教程】  如何用美橙互联一键搭建多站合一网站?  如何基于PHP生成高效IDC网络公司建站源码?  如何快速查询域名建站关键信息?  网站建设要注意的标准 促进网站用户好感度!  公司网站制作价格怎么算,公司办个官网需要多少钱?  php打包exe后无法访问网络共享_共享权限设置方法【教程】  1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤  高防服务器租用如何选择配置与防御等级?  长沙企业网站制作哪家好,长沙水业集团官方网站?  Laravel如何生成URL和重定向?(路由助手函数)  Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】  瓜子二手车官方网站在线入口 瓜子二手车网页版官网通道入口  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  HTML5空格在Angular项目里怎么处理_Angular中空格的渲染问题【详解】  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知  Laravel用户密码怎么加密_Laravel Hash门面使用教程  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  Python结构化数据采集_字段抽取解析【教程】  Laravel如何使用.env文件管理环境变量?(最佳实践)  网站制作价目表怎么做,珍爱网婚介费用多少?  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  Bootstrap整体框架之CSS12栅格系统  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  Thinkphp 中 distinct 的用法解析  厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?  Swift中循环语句中的转移语句 break 和 continue  Android 常见的图片加载框架详细介绍  Laravel如何使用查询构建器?(Query Builder高级用法)  BootStrap整体框架之基础布局组件  Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】  详解Huffman编码算法之Java实现  千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】  青岛网站建设如何选择本地服务器?  专业商城网站制作公司有哪些,pi商城官网是哪个?  在centOS 7安装mysql 5.7的详细教程  齐河建站公司:营销型网站建设与SEO优化双核驱动策略  JavaScript中的标签模板是什么_它如何扩展字符串功能  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  如何在景安服务器上快速搭建个人网站?  微信小程序制作网站有哪些,微信小程序需要做网站吗?  Laravel如何与Pusher实现实时通信?(WebSocket示例)  微信小程序 scroll-view组件实现列表页实例代码  javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】  高端智能建站公司优选:品牌定制与SEO优化一站式服务  laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法  Laravel如何实现多表关联模型定义_Laravel多对多关系及中间表数据存取【方法】