码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • c++新特性 智能指针和内存管理


    前言:

    了解 Objective-C/Swift 的程序员应该知道引用计数的概念。引用计数这种计数是为了防止内存泄 露而产生的。基本想法是对于动态分配的对象,进行引用计数,每当增加一次对同一个对象的引用,那 么引用对象的引用计数就会增加一次,每删除一次引用,引用计数就会减一,当一个对象的引用计数减 为零时,就自动删除指向的堆内存。我们在构造函数的时候申请空间,而在析构函数(在 离开作用域时调用)的时候释放空间,也就是我们常说的 RAII 资源获取即初始化技术。

    我们总会有需要将对象在自由存储上分配的需求,在传统 C++ 里我们只好使用 new 和 delete 去『记得』对资源进行释放。而 C++11 引入了智能指针的概念,使用了引用计数的想法,让程序 员不再需要关心手动释放内存

    智能指针

    std::share_ptr

    std::shared_ptr 是一种智能指针,它能够记录多少个 shared_ptr 共同指向一个对象,从而消除 显示的调用 delete,当引用计数变为零的时候就会将对象自动删除。

    但还不够,因为使用 std::shared_ptr 仍然需要使用 new 来调用,这使得代码出现了某种程度上的 不对称。 std::make_shared 就能够用来消除显式的使用 new,所以 std::make_shared 会分配创建传入参 数中的对象,并返回这个对象类型的 std::shared_ptr 指针。例如

    1. #include
    2. #include
    3. void foo(std::shared_ptr<int>i)
    4. {
    5. (*i)++;
    6. }
    7. int main()
    8. {
    9. //auto pointer=new int(10) 非法,不能直接分配
    10. auto pointer=std::make_shared<int>(10);
    11. foo(pointer);
    12. std::cout<<*pointer<
    13. auto pointer1=pointer;
    14. auto pointer2=pointer;
    15. int *p=pointer.get();
    16. std::cout<<*p<<"\n";
    17. std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 3
    18. std::cout << "pointer1.use_count() = " << pointer1.use_count() << std::endl; // 3
    19. std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; //
    20. pointer2.reset();
    21. std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 3
    22. std::cout << "pointer1.use_count() = " << pointer1.use_count() << std::endl; // 3
    23. std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; //
    24. }

    结果:

    11
    11
    pointer.use_count() = 3
    pointer1.use_count() = 3
    pointer2.use_count() = 3
    pointer.use_count() = 2
    pointer1.use_count() = 2
    pointer2.use_count() = 0

    make_share<>():制造share_ptr;

    std::shared_ptr 可以通过 get() 方法来获取原始指针,通过 reset() 来减少一个引用计数,并 通过 use_count() 来查看一个对象的引用计数

    std::unique_ptr

    std::unique_ptr 是一种独占的智能指针,它禁止其他智能指针与其共享同一个对象

    既然是独占,换句话说就是不可复制。但是,我们可以利用 std::move 将其转移给其他的 unique_ptr

    代码如下:

    1. #include
    2. #include
    3. struct Foo
    4. {
    5. Foo() { std::cout << "Foo::Foo" << std::endl; }
    6. ~Foo() { std::cout << "Foo::~Foo" << std::endl; }
    7. void foo() { std::cout << "Foo::foo" << std::endl; }
    8. };
    9. void f(const Foo&)
    10. {
    11. std::cout<<"f(const Foo)"<
    12. }
    13. int main()
    14. {
    15. std::unique_ptrp1(std::make_unique());
    16. if(p1)p1->foo();
    17. {
    18. std::unique_ptr p2(std::move(p1));
    19. f(*p2);
    20. if(p2)p2->foo();
    21. if(p1)p1->foo();
    22. p1 = std::move(p2);
    23. // p2 为空, 无输出
    24. if(p2) p2->foo();
    25. std::cout << "p2 被销毁" << std::endl;
    26. }
    27. if (p1) p1->foo();
    28. }

    Foo::Foo
    Foo::foo
    f(const Foo)
    Foo::foo
    p2 被销毁
    Foo::foo
    Foo::~Foo

    疑点:为什么p1没有重新构建 ,p2没有销毁?

    首先unique_ptr的目的是禁止复制,我们所用的是std::move,实现转移,所以对象一直存在(内存空间),离开实例时候消失。

    std::weak_ptr

    如果你仔细思考 std::shared_ptr 就会发现依然存在着资源无法释放的问题

    1. #include
    2. #include
    3. struct A;
    4. struct B;
    5. struct A {
    6. std::shared_ptr pointer;
    7. ~A() {
    8. std::cout << "A 被销毁" << std::endl;
    9. }
    10. };
    11. struct B {
    12. std::shared_ptr pointer;
    13. ~B() {
    14. std::cout << "B 被销毁" << std::endl;
    15. }
    16. };
    17. int main() {
    18. auto a = std::make_shared();
    19. auto b = std::make_shared();
    20. a->pointer = b;
    21. b->pointer = a;
    22. }

     结果如图:

     

     运行过程:

    分析: 运行结果是 A, B 都不会被销毁,这是因为 a,b 内部的 pointer 同时又引用了 a,b,这使得 a,b 的引 用计数均变为了 2,而离开作用域时,a,b 智能指针被析构,却只能造成这块区域的引用计数减一,这样 就导致了 a,b 对象指向的内存区域引用计数不为零,而外部已经没有办法找到这块区域了,也就造成了 内存泄露

    可以应用

    1. #include
    2. #include
    3. struct A;
    4. struct B;
    5. struct A {
    6. std::shared_ptr pointer;
    7. ~A() {
    8. std::cout << "A 被销毁" << std::endl;
    9. }
    10. };
    11. struct B {
    12. std::weak_ptr pointer;
    13. ~B() {
    14. std::cout << "B 被销毁" << std::endl;
    15. }
    16. };
    17. int main() {
    18. auto a = std::make_shared();
    19. auto b = std::make_shared();
    20. a->pointer = b;
    21. b->pointer = a;
    22. }

    结果:

     运行过程:

     解决这个问题的办法就是使用弱引用指针 std::weak_ptr,std::weak_ptr 是一种弱引用(相比较 而言 std::shared_ptr 就是一种强引用)。弱引用不会引起引用计数增加

    在上图中,最后一步只剩下 B,而 B 并没有任何智能指针引用它,因此这块内存资源也会被释放

  • 相关阅读:
    [网鼎杯 2020 青龙组]bang 题解
    wangEditor 粘贴从 word 复制的带图片内容的最佳实践
    Docker常用命令记录
    计算点云每个点的粗糙度(附open3d python代码)
    unity3d客户端框架 基于类对象池的可回收变量 代码实现
    帆软FineReport决策报表Tab实现方案
    Docker 大热,还不了解 Dockerfile 你就OUT啦~
    Gradle系列——Gradle文件操作,Gradle依赖(基于Gradle文档7.5)day3-1
    Android 15新特性,强制edge-to-edge全面屏体验
    java计算机毕业设计建筑劳务监管平台MyBatis+系统+LW文档+源码+调试部署
  • 原文地址:https://blog.csdn.net/qq_62309585/article/details/126753586
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号