news 2026/5/6 19:47:42

SharedPtr测试步骤说明

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SharedPtr测试步骤说明

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、前置准备
    • 1. 带行号的测试代码
    • 2. 核心规则(对应我们的 `SharedPtr` 实现)
  • 二、逐行执行解析
    • 行1:打印标题
    • 行2:构造`sp1`,托管字符串对象
    • 行3:解引用并打印计数
    • 行4:拷贝构造`sp2`,共享`sp1`的资源
    • 行5:打印`sp2`的值和计数
    • 行6:`sp1`调用`reset`,切换托管对象
    • 行7:打印`sp1`新对象的信息
    • 行8:打印`sp2`的信息
    • 行9:移动构造`sp3`,转移`sp1`的所有权
    • 行10~11:判断`sp1`是否为空并打印
    • 行12:打印`sp3`的信息
  • 三、函数结束:析构阶段(隐式执行)
  • 四、总结

结合我们自定义实现的SharedPtr,我将完整拆解test_shared_ptr测试函数的每一行执行逻辑、内存状态、引用计数变化、输出结果,并对应到类的实现原理说明原因。

一、前置准备

1. 带行号的测试代码

// 测试SharedPtrvoidtest_shared_ptr(){std::cout<<"\n===== 测试SharedPtr ====="<<std::endl;// 行1SharedPtr<std::string>sp1(newstd::string("Hello"));// 行2std::cout<<*sp1<<",强引用计数:"<<sp1.use_count()<<std::endl;// 行3SharedPtr<std::string>sp2=sp1;// 拷贝构造 行4std::cout<<*sp2<<",强引用计数:"<<sp1.use_count()<<std::endl;// 行5sp1.reset(newstd::string("World"));// 行6std::cout<<*sp1<<",强引用计数:"<<sp1.use_count()<<std::endl;// 行7std::cout<<*sp2<<",强引用计数:"<<sp2.use_count()<<std::endl;// 行8SharedPtr<std::string>sp3=std::move(sp1);// 移动构造 行9if(sp1.get()==nullptr){// 行10std::cout<<"sp1移动后为空"<<std::endl;// 行11}std::cout<<*sp3<<",强引用计数:"<<sp3.use_count()<<std::endl;// 行12}

2. 核心规则(对应我们的SharedPtr实现)

  1. 构造新指针:绑定原始指针时,创建RefCount对象,强引用计数初始化为 1
  2. 拷贝构造/赋值:共享资源和计数,强引用计数 +1
  3. 移动构造/赋值:转移所有权,计数不变化,原指针置空;
  4. reset()/析构:调用release(),强引用计数 -1;计数为0时,释放托管的堆内存;
  5. use_count():返回当前强引用计数,无资源时返回0

二、逐行执行解析

行1:打印标题

std::cout<<"\n===== 测试SharedPtr ====="<<std::endl;
  • 操作:控制台输出分割标题,无内存操作;
  • 结果:控制台打印===== 测试SharedPtr =====
  • 原因:标准输出流的常规打印逻辑。

行2:构造sp1,托管字符串对象

SharedPtr<std::string>sp1(newstd::string("Hello"));
  • 操作
    1. 在堆上创建std::string("Hello")对象;
    2. 调用SharedPtr的有参构造函数,sp1托管该对象;
    3. 新建RefCount对象,strong_ref = 1
  • 内存状态
    • sp1.ptr_→ 堆上的"Hello"字符串;
    • sp1.ref_count_→ 计数对象,强引用=1;
  • 结果sp1成为第一个托管该字符串的智能指针;
  • 原因:构造函数中,非空指针会初始化引用计数为1,标记当前只有1个所有者。

行3:解引用并打印计数

std::cout<<*sp1<<",强引用计数:"<<sp1.use_count()<<std::endl;
  • 操作
    1. 重载operator*,获取sp1托管的字符串值;
    2. 调用use_count(),读取强引用计数;
  • 输出结果Hello,强引用计数:1
  • 原因
    • *sp1直接访问托管的字符串内容Hello
    • 当前仅sp1持有资源,计数为1

行4:拷贝构造sp2,共享sp1的资源

SharedPtr<std::string>sp2=sp1;
  • 操作:调用拷贝构造函数sp2sp1共享同一块内存和计数对象,强引用计数 +1
  • 内存状态
    • sp1sp2ptr_都指向"Hello"
    • 共享的计数对象strong_ref = 2
  • 结果:两个智能指针共享同一个资源;
  • 原因:拷贝构造的核心逻辑是共享所有权,计数加1表示新增一个资源所有者。

行5:打印sp2的值和计数

std::cout<<*sp2<<",强引用计数:"<<sp1.use_count()<<std::endl;
  • 输出结果Hello,强引用计数:2
  • 原因
    • sp2sp1指向同一字符串,解引用结果都是Hello
    • 计数对象共享,无论用sp1还是sp2调用use_count(),结果都为2

行6:sp1调用reset,切换托管对象

sp1.reset(newstd::string("World"));
  • 操作reset函数逻辑):
    1. 调用release():原计数2 → 1计数不为0,不释放"Hello"内存
    2. 在堆上创建新字符串"World"
    3. sp1绑定新对象,创建新的计数对象,强引用计数重置为1
  • 内存状态
    • sp1:指向"World",计数=1;
    • sp2:仍指向"Hello",计数=1;
  • 结果sp1sp2彻底分离,各自托管独立资源;
  • 原因reset会先释放当前所有权(计数减1),再接管新资源,计数归1。

行7:打印sp1新对象的信息

std::cout<<*sp1<<",强引用计数:"<<sp1.use_count()<<std::endl;
  • 输出结果World,强引用计数:1
  • 原因sp1已切换到新字符串World,且是该资源的唯一所有者,计数为1

行8:打印sp2的信息

std::cout<<*sp2<<",强引用计数:"<<sp2.use_count()<<std::endl;
  • 输出结果Hello,强引用计数:1
  • 原因sp2未被修改,依旧持有原Hello字符串,且是唯一所有者,计数为1

行9:移动构造sp3,转移sp1的所有权

SharedPtr<std::string>sp3=std::move(sp1);
  • 操作:调用移动构造函数,将sp1的指针、计数对象转移sp3
    • 计数数值不发生变化
    • sp1ptr_ref_count_置为nullptr
  • 内存状态
    • sp3:指向"World",计数=1;
    • sp1:空指针,无计数对象;
  • 结果:所有权从sp1转移给sp3sp1失效;
  • 原因:移动语义是所有权转移,而非共享,因此不修改引用计数,仅清空原对象。

行10~11:判断sp1是否为空并打印

if(sp1.get()==nullptr){std::cout<<"sp1移动后为空"<<std::endl;}
  • 操作get()返回原始指针,判断是否为nullptr
  • 输出结果sp1移动后为空
  • 原因:移动构造后,sp1的内部指针被主动置空,不再持有任何资源。

行12:打印sp3的信息

std::cout<<*sp3<<",强引用计数:"<<sp3.use_count()<<std::endl;
  • 输出结果World,强引用计数:1
  • 原因sp3接管了sp1的资源,是World的唯一所有者,计数保持1

三、函数结束:析构阶段(隐式执行)

test_shared_ptr函数执行完毕,栈上的sp1/sp2/sp3依次析构,触发SharedPtr析构函数:

  1. sp1:已为空,无任何操作;
  2. sp2:计数1→0,释放Hello字符串内存;
  3. sp3:计数1→0,释放World字符串内存;
    最终所有堆内存都被自动释放,无内存泄漏

四、总结

  1. 拷贝=共享所有权:计数+1,多个指针管理同一块内存,计数为0才释放资源;
  2. 移动=转移所有权:计数不变,原指针置空,是更高效的所有权传递方式;
  3. reset=主动释放+重新绑定:先放弃旧资源(计数-1),再托管新对象;
  4. 引用计数是核心:所有共享指针的行为,都围绕强引用计数的增减判断内存释放时机。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 12:46:04

计算机SSM毕设实战-基于ssm的社区外来务工人员管理系统的设计与实现人员信息登记、居住管理、就业跟踪、服务申请【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/5/5 3:16:49

SSM毕设选题推荐:基于ssm的社区外来务工人员管理系统的设计与实现基于Java+SSM的社区外来务工人员管理系统【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/5/2 22:32:41

社会网络仿真软件:UCINET_(10).网络演化模型

网络演化模型 在网络分析中&#xff0c;网络演化模型是一种重要的工具&#xff0c;用于模拟和分析网络结构随时间变化的过程。这些模型可以帮助我们理解网络中的动态行为&#xff0c;预测未来的变化趋势&#xff0c;并为决策提供依据。UCINET 提供了多种方法来构建和分析网络演…

作者头像 李华
网站建设 2026/5/2 14:57:54

AI原生应用领域多租户技术的创新实践

AI原生应用领域多租户技术的创新实践 关键词&#xff1a;AI原生应用、多租户技术、资源隔离、动态调度、数据隐私 摘要&#xff1a;本文围绕AI原生应用中的多租户技术展开&#xff0c;从核心概念到实战落地&#xff0c;结合生活案例与技术细节&#xff0c;深入解析多租户技术如…

作者头像 李华
网站建设 2026/5/3 10:22:17

555555

555555

作者头像 李华
网站建设 2026/4/25 3:17:09

社会网络仿真软件:UCINET_(8).结构洞与社会资本分析

结构洞与社会资本分析 1. 结构洞的定义与重要性 结构洞&#xff08;Structural Holes&#xff09;是指在社会网络中&#xff0c;两个或多个节点之间没有直接的连接&#xff0c;但通过一个中介节点间接相连。这些中介节点在信息、资源和机会的传递中扮演着关键角色&#xff0c…

作者头像 李华