0

0

C++中智能指针的循环引用问题 解决方案与最佳实践

P粉602998670

P粉602998670

发布时间:2025-07-07 09:20:02

|

657人浏览过

|

来源于php中文网

原创

循环引用是指两个或多个shared_ptr对象彼此持有对方的强引用,导致引用计数无法归零,内存无法释放。1. 例如,结构体a和b各自持有对方的shared_ptr,形成闭环;2. 解决方法是将其中一方改为使用weak_ptr,打破强引用循环;3. 最佳实践包括:优先使用智能指针、需要互相引用时用weak_ptr、避免直接将this赋值给shared_ptr、合理使用enable_shared_from_this、注意容器中的循环引用问题。通过明确资源拥有者与观察者的关系,可有效避免此类内存泄漏。

C++中智能指针的循环引用问题 解决方案与最佳实践

在C++中,智能指针是管理动态内存的好工具,但如果不小心使用,很容易遇到“循环引用”问题。这会导致内存无法释放,造成泄漏。尤其是shared_ptr之间互相持有对方的引用时,问题尤为明显。

C++中智能指针的循环引用问题 解决方案与最佳实践

解决这个问题的关键在于:避免不必要的强引用,以及合理使用弱指针 weak_ptr

C++中智能指针的循环引用问题 解决方案与最佳实践

什么是循环引用?

简单来说,就是两个或多个shared_ptr对象彼此持有对方的引用,导致它们的引用计数永远不为0,从而无法被释放。

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

举个例子:

C++中智能指针的循环引用问题 解决方案与最佳实践
struct B;

struct A {
    std::shared_ptr b_ptr;
};

struct B {
    std::shared_ptr a_ptr;
};

int main() {
    auto a = std::make_shared();
    auto b = std::make_shared();
    a->b_ptr = b;
    b->a_ptr = a;
}

在这个例子中,ab相互持有对方的shared_ptr,即使超出作用域,它们的引用计数也不会归零,结果就是内存永远不会被释放。


如何解决循环引用?

解决循环引用的核心思路是:把其中一方改为使用 weak_ptr。因为weak_ptr不会增加引用计数,这样就能打破循环。

修改上面的例子如下:

Revid AI
Revid AI

AI短视频生成平台

下载
struct B;

struct A {
    std::shared_ptr b_ptr;
};

struct B {
    std::weak_ptr a_ptr; // 改成 weak_ptr
};

int main() {
    auto a = std::make_shared();
    auto b = std::make_shared();
    a->b_ptr = b;
    b->a_ptr = a;
}

这时,当a离开作用域,它的引用计数会正常减到0并释放资源,b也会随之释放。


使用智能指针的最佳实践

为了避免类似问题,在日常开发中可以遵循以下几个原则:

  • 尽量少用裸指针,优先使用智能指针来管理资源。
  • 需要互相引用时,至少一方使用 weak_ptr
  • 不要随意将 this 赋值给 shared_ptr,容易造成循环或悬空指针,可以用 enable_shared_from_this 来安全获取当前对象的 shared_ptr
  • 注意容器中的智能指针循环,比如在树形结构、图结构中,父子节点之间容易出现这种情况。

例如:

class Node : public std::enable_shared_from_this {
public:
    std::shared_ptr parent;
    std::vector> children;

    void addChild(std::shared_ptr child) {
        child->parent = shared_from_this(); // 安全地获取当前对象的 shared_ptr
        children.push_back(child);
    }
};

这时候子节点持有父节点的shared_ptr没问题,但父节点也持有子节点的shared_ptr,如果子节点又反过来引用父节点,就可能出现循环。所以可以考虑让父节点用weak_ptr保存子节点(视具体需求而定)。


小结一下

智能指针虽然方便,但也不是万能的。尤其是在有复杂关系的数据结构中,循环引用是一个常见但容易忽略的问题。

解决方式其实并不复杂,主要是:

  • 明确谁拥有资源,谁只是观察者
  • 在观察者角色中使用 weak_ptr
  • 合理使用 enable_shared_from_this

只要在设计阶段多加注意,这类问题是可以完全避免的。

基本上就这些了。

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

193

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

185

2025.07.04

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

529

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

6

2025.12.22

空指针异常处理
空指针异常处理

本专题整合了空指针异常解决方法,阅读专题下面的文章了解更多详细内容。

20

2025.11.16

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

php网站源码教程大全
php网站源码教程大全

本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。

4

2025.12.31

视频文件格式
视频文件格式

本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

不受国内限制的浏览器大全
不受国内限制的浏览器大全

想找真正自由、无限制的上网体验?本合集精选2025年最开放、隐私强、访问无阻的浏览器App,涵盖Tor、Brave、Via、X浏览器、Mullvad等高自由度工具。支持自定义搜索引擎、广告拦截、隐身模式及全球网站无障碍访问,部分更具备防追踪、去谷歌化、双内核切换等高级功能。无论日常浏览、隐私保护还是突破地域限制,总有一款适合你!

7

2025.12.31

热门下载

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

精品课程

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号