• 用幻灯片讲解C++手动内存管理


    C++手动内存管理

    1.栈内存的基本元素

    在这里插入图片描述

    2.栈内存的聚合对象

    在这里插入图片描述

    3.手动分配内存和释放内存

    注意:手动分配内存,指的是在堆内存中。
    除非实现自己的数据结构,否则永远不要手动分配内存!
    即使这样,您也应该通过std::allocator_traits使用分配器。(注:allocator_traits是STL库的对自定义内存分配器的统一接口)
    在这里插入图片描述

    4.在堆上手动分配内存

    p被当做拥有一个原始指针。这幅幻灯片有个bug,不知各位看出来没有?
    在这里插入图片描述

    5.手动分配数组内存和释放数组内存

    注意:释放数组内存delete后一定要带[ ],否则程序将产生不可预知的后果,大概率是报内存错误后程序挂掉,因为你只释放了数组的一个元素的内存,其它内存没有释放,造成了内存泄漏。
    作者再次强调了:
    除非实现自己的数据结构,否则永远不要手动分配内存!
    即使这样,您也应该通过std::allocator_traits使用分配器。
    在这里插入图片描述

    6.手动分配数组内存

    在这里插入图片描述

    7.不要使用拥有的原始指针

    • 指针指向已经删除的内存怎么办?
    • 如果指针指向其他进程保留的内存怎么办?
    • 我们必须手动跟踪分配(new)和解除分配(delete)
    • 非常容易出错,可能导致难以捕捉的bug

    下图就是一个经典的错误,释放内存后,用户忘记了已经释放,然后又向p指向的内存写入值,产生内存错误,程序挂掉!
    在这里插入图片描述

    8.黑暗时代和现代C++时代

    黑暗时代(C++11之前)

    • 拥有原始指针
    • 经常在不同的代码点显式的new和显示的delete
    • 非直观界面
    • 内存易泄漏

    现代C++时代

    智能指针
    • 自动删除对象
    • 自我文档化接口/所有权(指由智能指针来管理内存,不需要用户关系具体细节)
    • 没有内存泄漏
      在这里插入图片描述

    9.地址检测器(ASAN)

    • 支持的编译器:g++、clang++
    • 检测内存错误
      • 内存泄漏
      • 访问已经释放的内存
      • 访问不正确的堆栈区域
    • 使用附加说明检测您的代码
      • 运行时间增加约70%
      • 内存使用量增加了大约3倍

    注:ASAN是谷歌开发的一个动态内存检测器,可以检测出各种内存相关的错误。
    在这里插入图片描述

    10.示例:检测空指针

    在这里插入图片描述

    11.使用ASAN

    在这里插入图片描述

    12.Valgrind工具

    (Valgrind 是一个强大的内存调试和性能分析工具集,广泛应用于 C/C++ 等编程语言的软件开发和分析中。)

    检测常见运行时错误。

    • 读/写释放的内存或不正确的堆栈区域。
    • 使用未初始化的值。
    • 不正确的内存释放,如双重释放。
    • 滥用内存分配函数。
    • 内存泄漏-无意内存泄漏通常与程序逻辑缺陷有关,这些缺陷导致内存指针在重新分配之前丢失。

    Windows:

    Dr.Memory (www.drmemory.org) (Windows平台上的C/C++内存错误检查器)
    Windows 10 64位:在WSL中的Valgrind
    在这里插入图片描述

    13.Valgrind使用

    在这里插入图片描述
    在这里插入图片描述

    14.标准库中的异常

    operator new 会抛出以下异常:

    • std::bad_alloc 如果内存没有被成功分配
    • std::bad_new_array_size 如果数组长度小于0或者太大
      在这里插入图片描述

    15.异常安全性的含义

    内存泄漏的潜在来源
    如下图的示例,如果文件不存在抛出异常后则就会造成buf指向的内存没有被释放,内存泄漏!
    在这里插入图片描述

    16.智能指针工程及其异常安全性

    • C++标准要求:
      • 所有函数参数必须在进入函数前求值。
      • 未指定函数参数求值顺序。
    • 6种参数求值顺序的两种。
      在这里插入图片描述

    下图可能会造成内存泄漏

    可能的求值顺序:

    1. new Widget{}
    2. Gadget{}
    3. unique_ptr{}

    如果Gadget构造函数抛出异常

    • Widget对象已经构建(在堆上)
    • unique_ptr尚未获取Widget对象的所有权
    • Widget对象泄漏
      在这里插入图片描述
      下图代码就不可能有内存泄露:
    • 调用make_unique()在Gadjet构造函数调用之前或之后完全计算。
    • 如果Gadget构造函数抛出异常:
      • 则Widget已经被unique_ptr所拥有,
      • 无论如何,Widget都会被正确地销毁。
    • 使用 make_unique和make_shared来创建智能指针!
      在这里插入图片描述
      希望文章对您有所帮助,整理不易,请随手点个赞!原文链接:hackingcpp.com
  • 相关阅读:
    Android字体大小dp,sp,px系统设置字体大小变化表现
    打印字符串数组中隐含的目录结构问题解法
    windows和linux下安装memcached
    使用Typecho搭建个人博客网站,并内网穿透实现公网访问——“cpolar内网穿透”
    盲盒小程序预售机制的设计与实施
    后厂村路灯:【干货分享】AppleDevelop苹果开发者到期重置
    压测——总结
    L2TP客户端之Strongswan移植(三)
    OpenCV-C++选择、提取感兴趣区域(ROI区域)【附用鼠标选取ROI区域的代码】
    存在已打开的MicrosoftEdge浏览器,无法执行安装
  • 原文地址:https://blog.csdn.net/silencestarsky/article/details/139481604