当前位置: 首页 > news >正文

C++ 智能指针代码解析

前言

如果在程序中使用new从堆分配内存,等到不再需要时,应使用delete将其释放,C++引入了智能指针auto_ptr,以帮助自动完成这个过程,但是aoto_ptr也有其局限性,因此从Boost库中又引入了三种智能指针unique_ptr shared_ptr weak_ptr。

1,aoto_ptr

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include <memory>

#include <string>

#include <iostream>

#include <ostream>

usingnamespacestd;

int_tmain(intargc, _TCHAR* argv[])

{

auto_ptr<string> ptr1(newstring("this is ptr!"));

auto_ptr<string> ptr2;

ptr2 = ptr1;

cout << &ptr2<<endl;

cout << *ptr2 << endl;

return0;

}

  • output :

003AFBC0
this is ptr!

但是如果输出的是ptr1,程序会如何呢?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#include "stdafx.h"

#include <memory>

#include <string>

#include <iostream>

#include <ostream>

usingnamespacestd;

int_tmain(intargc, _TCHAR* argv[])

{

auto_ptr<string> ptr1(newstring("this is ptr!"));

auto_ptr<string> ptr2;

ptr2 = ptr1;

cout << &ptr1 <<endl;

cout << *ptr1 << endl; #这一步程序会崩溃

return0;

}

崩溃原因: 首先ptr2 = ptr1表示ptr1将访问的权限给了ptr2,同时意味了ptr1已经没有访问字符串的权限,因此会报错。

那如何解决这个问题呢?引入了unique_ptr

2,unique_ptr

1

2

3

4

5

6

7

8

9

10

11

12

13

#include "stdafx.h"

#include <memory>

#include <string>

#include <iostream>

#include <ostream>

usingnamespacestd;

int_tmain(intargc, _TCHAR* argv[])

{

unique_ptr<string> ptr1(newstring("this is unique_ptr"));

unique_ptr<string> ptr2;

ptr2 = ptr1; #这一步编译器会报错

return0;

}

unique_ptr 替代auto_ptr实现独占式,可以理解成,同一时刻只能有一个unique_ptr指向给定对象,unique_ptr对象始终是关联的原始指针的唯一所有者。无法复制unique_ptr对象,它只能移动。(这样可以保证,不会出现auto_ptr那样运行时会出现的隐藏内存崩溃问题)

1

2

3

4

5

6

7

8

9

10

int_tmain(intargc, _TCHAR* argv[])

{

unique_ptr<string> ptr1(newstring("this is unique_ptr"));

unique_ptr<string> ptr2;

cout << &ptr1 << endl;

unique_ptr<string> ptr3(newstring("other unique_ptr"));

cout << &ptr3 << endl;

cout << *ptr3 << endl;

return0;

}

  • output:

00D9F8B4
00D9F89C
other unique_ptr

3,share_ptr

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include <memory>

#include <string>

#include <iostream>

#include <ostream>

usingnamespacestd;

classbase{

public:

base()

{

cout <<"begin..."<< endl;

};

~base()

{

cout <<"end..."<< endl;

}

};

int_tmain(intargc, _TCHAR* argv[])

{

base *a =newbase();

shared_ptr<base> ptr1(a);

//shared_ptr<base> ptr2(a); ## 如果加上这句程序会崩溃,双重管理陷阱,a对象被删除了两次

return0;

}

  • output:

begin...

end...

  • share_ptr的循环陷阱

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

#include "stdafx.h"

#include <memory>

#include <string>

#include <iostream>

#include <ostream>

usingnamespacestd;

classCB;

classCA

{

public:

CA()

{

cout <<"CA call ..."<< endl;

}

~CA()

{

cout <<"~CA call..."<< endl;

}

voidsetPtr(shared_ptr<CB> &ptr)

{

m_ptr_b = ptr;

}

intgetCount()

{

returnm_ptr_b.use_count();

}

private:

shared_ptr<CB> m_ptr_b;

};

classCB

{

public:

CB()

{

cout <<"CB call..."<< endl;

}

~CB()

{

cout <<"~CB call..."<< endl;

}

voidsetPtr(shared_ptr<CA> ptr)

{

m_ptr_a = ptr;

}

intgetCount()

{

returnm_ptr_a.use_count();

}

private:

shared_ptr<CA> m_ptr_a;

};

int_tmain(intargc, _TCHAR* argv[])

{

shared_ptr<CA> ptr_a(newCA);

shared_ptr<CB> ptr_b(newCB);

cout <<" CA count is : "<< ptr_a->getCount()<<endl;

cout <<"CB count is:"<< ptr_b->getCount()<< endl;

ptr_a->setPtr(ptr_b);

ptr_b->setPtr(ptr_a);

cout <<" CA count is : "<< ptr_a->getCount() << endl;

cout <<"CB count is:"<< ptr_b->getCount() << endl;

return0;

}

上面这段程序的思路用下面张图可以清晰的表示

图片和代码主要参考的是这篇很棒的博文:智能指针(三):weak_ptr浅析

运行结果后发现并没有调用析构函数释放内存,以后存在内存泄漏的风险

那如何去解决这个问题呢?,可以通过引入weak_ptr来解决,但是weak_ptr需要与share_ptr配合使用

4, weak_ptr

通过在两个类中的一个成员变量改为weak_ptr对象,因为weak_ptr不会增加引用计数,使得引用形不成环,最后就可以正常的释放内部的对象,不会造成内存泄漏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

classCB

{

public:

CB()

{

cout <<"CB call..."<< endl;

}

~CB()

{

cout <<"~CB call..."<< endl;

}

voidsetPtr(shared_ptr<CA> ptr)

{

m_ptr_a = ptr;

}

intgetCount()

{

returnm_ptr_a.use_count();

}

private:

///shared_ptr<CA> m_ptr_a;

weak_ptr<CA> m_ptr_a; ## 改为weak_ptr对象

};

总结

遇到这类新的概念或者方法时,一定要不嫌麻烦的一行一行代码的去敲,在敲的过程中去理解吸收,如果只看不实践,很有可能理解不深刻,无法体会到其中的原理和机制,所以对待问题一定要沉下心来多实践。

http://www.jsqmd.com/news/717886/

相关文章:

  • VS Code MCP生态冷启动避坑图谱:从零搭建可商用MCP服务栈的6个关键决策点(含架构选型矩阵)
  • NEURAL MASK 学术写作助手:自动生成论文中的技术示意图与图表
  • Banana Pi BPI-F4工业级边缘AI开发板解析与应用
  • 提示的错误为Saving Environment to FAT ... Unable to use mmc 0:1... Failed(1)
  • 什么样的人,才算真正的 AI 产品评测专家?
  • 从零开始:HS2-HF_Patch游戏增强补丁完全配置指南
  • QueryWrapper和LambdaQueryWrapper
  • 5步解锁免费VIP音乐体验:MoeKoeMusic跨平台播放器完全指南
  • MedGemma X-Ray 快速入门:小白也能用的医疗影像AI助手
  • TradingView Lightweight Charts:5分钟构建高性能金融图表应用
  • ITSS 项目服务经理:报考条件 + 报考全流程
  • Embedding 学习笔记
  • Si826x数字隔离门驱动器:工业电机控制的高效解决方案
  • Kubernetes攻防 特殊路径挂载导致的容器逃逸
  • 《池上》唐·白居易
  • Linux系统下的深度学习环境配置:从入门到精通
  • 启动mysql失败/usr/libexec/mysqld: Operation not permitted
  • 零基础玩转Qwen2.5-VL-7B:RTX 4090专属视觉助手,开箱即用图文交互
  • Python + FastAPI+ uniapp 健身房预约系统
  • 图形验证码的技术原理与应用场景深度解析
  • OpenClaw 安全复盘:“龙虾”漏洞到底发生了什么?
  • 2026年国内数字化档案管理系统Top5推荐
  • 别再为水下AI发愁了!手把手教你用虎鲸开源的UATD声呐数据集(含10类目标、9200张图)
  • 3步搭建零成本眼动追踪系统:eyeLike开源项目完全指南
  • Pixel Aurora Engine 模拟电路设计辅助:Proteus仿真图智能生成案例
  • 如何通过智能清理工具彻底解决Windows系统卡顿问题:专业指南
  • 【AI开发工具】Anaconda 完整安装与使用教程
  • 一年读完12本书,硬核搞定AI大模型入门!建议收藏!
  • 别再只调超参了!给ResNet50加上SE模块,我的图像分类准确率提升了3%
  • 2026上半年最值得关注的10款IT运维软件