• 深入理解C++智能指针系列(一)


    引言

    都知道C/C++的最难的就是需要程序员自己管理内存,往往会因为一个简单的逻辑错误导致内存管理异常。
    通常内存管理过程中会遇到以下问题:

    1. 内存泄漏

    当开发者忘记释放已分配的内存时,就会发生内存泄漏。这种情况在大型项目中非常常见,项目中存在大量动态内存操作时,很容易遗漏释放操作。

    1. 空悬指针

    当一个指针被释放后继续被使用,它就变成了空悬指针。这种指针指向已被释放的内存,继续使用这种指针会导致不可预测的行为和程序崩溃。

    1. 双重释放

    如果同一个内存地址被释放多次,会发生双重释放错误,这可能导致程序崩溃或其他问题。

    1. 不匹配的分配/释放

    使用new分配内存时应该使用delete来释放,对于使用new[]分配的数组应该用delete[]来释放。如果这些操作不匹配,也会导致不可预测的行为或崩溃。

    正文

    为了减轻程序员对内存管理的难度和负担,C++11引入了智能指针。
    本文作为智能指针的第一篇,将从内存管理的基础来逐渐深入介绍智能指针。

    栈内存和堆内存

    和其他语言一样,C++有多重类型的内存,它们对应于物理内存的不同部分,分别是:静态、栈、堆。
    静态内存是一个非常复杂的话题,这里不过多关注,我们主要关注栈内存和堆内存。

    栈内存

    栈是一种遵循后进先出(LIFO,Last In First Out)原则的数据结构,用于存储局部变量和函数调用的信息。

    特点
    • 速度快:栈内存的分配和回收速度非常快。内存分配简单,因为它只涉及指针的移动。
    • 自动管理:函数执行完毕后,栈帧会自动弹出,局部变量也随之被销毁,程序员不需要手动管理这部分内存。
    • 空间限制:栈的大小通常有限,并且由操作系统预先定义。因此,大量数据或者不确定大小的数据不适合在栈上分配。
    限制
    • 由于空间有限,大型数据结构不应该存储在栈内存中,避免栈溢出
    • 栈内存中的数据不能被随意地访问或返回给函数外部,因为它们在函数返回后就不再存在了

    堆内存

    堆内存是一个用于动态内存分配的区域,程序在运行时可以从堆中分配或释放内存。与栈内存不同,堆内存的使用没有固定的模式,分配和释放顺序可以不一致。

    特点
    • 灵活性:堆允许程序动态地分配和释放内存,非常适合存储生命周期不确定或大小可变的数据对象。
    • 容量大:相比栈内存,堆的大小通常只受可用系统内存的限制。
    • 手动管理:程序员负责分配和释放堆内存。这提供了使用灵活性,但也增加了错误发生的风险,如内存泄漏或指针错误。
    缺点
    • 管理复杂:需要程序员显式地管理内存,易出错。
    • 效率较低:相比栈内存的操作,堆内存分配和回收的成本较高,因为涉及到更复杂的内存管理和可能的碎片化问题。
    • 安全性问题:不当的内存管理可能导致安全漏洞,如缓冲区溢出和无效指针访问。

    RAII

    RAII(Resource Acquisition Is Initialization)是一种编程中的设计模式,用于在面向对象的编程中管理资源(如内存、文件句柄、网络连接等)的生命周期。这个模式通过确保资源的获取与对象的生命周期同步,从而实现资源的自动管理,主要目的是减少内存泄漏和资源泄漏的风险。

    RAII的核心原则

    1. 资源封装在对象中

    RAII 模式通过将资源封装在拥有确定生命周期的对象中来管理资源。资源的分配(获取)发生在对象的构造过程中,而资源的释放发生在对象的析构过程中。

    1. 自动资源管理

    利用 C++ 的构造函数和析构函数,RAII确保只要对象还在作用域内,其管理的资源就会被正确维护,并在对象生命周期结束时自动释放。这消除了手动释放资源的需求,减少了因遗忘释放资源而导致的内存泄漏。

    1. 异常安全保证

    RAII 也增强了代码的异常安全性,因为当异常发生时,局部对象会按照构造的逆序自动销毁,其析构函数将被调用以释放资源,从而防止资源泄露。

    智能指针正是应用了RAII的设计模式来实现自动管理内存。

  • 相关阅读:
    顶级手机数据恢复软件 [2024 更新]
    【每日前端面经】2024-03-10
    阿里云历时13年,站上世界现代计算架构之巅
    C++之operator()和构造函数区别与总结(二百三十)
    【黑马云盘 Debug】ASSERT: “i >= 0 && i < size()“
    第二期:链表经典例题(两数相加,删除链表倒数第N个节点,合并两个有序列表)
    JUC并发编程与源码分析笔记03-CompletableFuture
    JavaSE数据类型
    【编程教室】PONG - 100行代码写一个弹球游戏
    【已解决】Splunk 8.2.X 升级ES 后红色报警
  • 原文地址:https://blog.csdn.net/LeoLei8060/article/details/139204803