5.关于delete[]

  1. 5.必备知识点-关于delete
    1. 5.1 知识点
      1. 知识回顾:如何在堆上释放内存
      2. 关于 delete[]
    2. 5.2 知识点代码
      1. MyClass.h
      2. 必备知识点4_关于delete.cpp

5.必备知识点-关于delete


5.1 知识点

知识回顾:如何在堆上释放内存

  • 使用 delete 关键字即可在堆上释放内存

  • 语法:

    • delete 指针变量 —— 配对 new
    • delete[] 数组变量 —— 配对 new[]
  • 作用:delete 的作用就是释放通过 new 在堆上分配的动态内存

关于 delete[]

  • 在使用 delete[] 时,一定要注意它只能释放连续存储的数组,一般用于由 new[] 创建的数组

举例说明:

// 1. MyClass* arr = new MyClass[5]; 
//    arr 是指向第一个对象的指针
//    堆中结构为
//    +-----------+-----------+-----------+-----------+-----------+
//    | MyClass 0 | MyClass 1 | MyClass 2 | MyClass 3 | MyClass 4 |
//    +-----------+-----------+-----------+-----------+-----------+
//    此时内存是连续的,我们可以用 delete[] 来进行释放
MyClass* arr = new MyClass[5];
delete[] arr;
arr = nullptr;
// 2. MyClass* arr[5];
//    arr 是一个栈上的指针数组
//    用来存储 5 个指针对象的数组,其中的元素需要我们手动 new
//    因此它们是不连续的,不能用 delete[] 来进行释放,需要遍历数组,单独释放每个元素
//    创建一个包含 5 个 MyClass 指针的数组(一级指针)
//    注意:这是一个在栈上分配的数组,数组本身的内存会在作用域结束时自动释放
//    但数组中存储的指针指向的对象是在堆上分配的
MyClass* arr2[5];

// 为每个数组元素分配一个 MyClass 对象(在堆上)
for (int i = 0; i < 5; i++)
    arr2[i] = new MyClass();

// 错误示例:不能使用 delete[] 释放栈上的数组
// arr2 是栈上的数组,其内存会在作用域结束时自动释放
// 使用 delete[] 会导致未定义行为(通常是程序崩溃)
// delete[] arr2;

// 正确做法:遍历数组,释放每个指针指向的堆上对象
for (int i = 0; i < 5; i++)
{
    if (arr2[i] != nullptr)
    {
        // 释放指针指向的 MyClass 对象(堆内存)
        delete arr2[i];
        // 将指针置空,避免成为野指针
        arr2[i] = nullptr;
    }
}

// 当作用域结束时,栈上的数组 arr2 会自动释放
// 但此时数组中的所有指针已被置为 nullptr
// 3. MyClass** arr = new MyClass*[5];
//    arr 是一个堆上的指针数组
//    arr 指向第一个元素,该元素存储的是指针对象,并不是 MyClass 对象
//    堆中结构为
//    +----------+----------+----------+----------+----------+
//    |  arr[0]  |  arr[1]  |  arr[2]  |  arr[3]  |  arr[4]  |
//    +----------+----------+----------+----------+----------+
//         ↓          ↓          ↓          ↓          ↓
//     指向实际 new 出来的 MyClass 对象(或为 nullptr)
//     MyClass地址  MyClass地址  MyClass地址  MyClass地址  MyClass地址
//    此时我们不仅需要 delete[] arr
//    还需要 delete 其中的每个元素
MyClass** arr3 = new MyClass*[5];

// 循环为每个指针元素分配实际的 MyClass 对象内存
for (int i = 0; i < 5; i++) {
    // 为每个指针分配 MyClass 实例的内存,arr3[i] 现在指向堆上的 MyClass 对象
    // 注意:此时形成了 “指针数组指向对象” 的二级内存结构
    arr3[i] = new MyClass();
}

// 内存释放阶段:先释放每个指针指向的对象,再释放指针数组本身
// 为什么先释放对象?因为如果先释放指针数组,会导致 arr3[i] 指针失效,无法再访问对象
for (int i = 0; i < 5; i++) {
    if (arr3[i] != nullptr) {
        // 释放单个 MyClass 对象的内存,避免内存泄漏
        // delete 会调用对象的析构函数,清理其内部资源
        delete arr3[i];
        // 将指针置为 nullptr,防止成为野指针(后续访问时可通过 nullptr 检查避免崩溃)
        arr3[i] = nullptr;
    }
}

// 释放指针数组本身的内存,该内存用于存储 5 个 MyClass* 指针
// delete[] 会释放 new[] 分配的连续内存,并正确处理数组大小(调用对应次数的析构函数)
delete[] arr3;
// 置为 nullptr 确保指针不再指向有效内存,避免误操作
arr3 = nullptr;

5.2 知识点代码

MyClass.h

#pragma once
class MyClass
{
};

必备知识点4_关于delete.cpp

#include <iostream>
#include "MyClass.h"
int main()
{
    #pragma region 知识回顾 如何在堆上释放内存
    //使用delete关键字 即可在堆上释放内存
    //语法:
    //delete 指针变量 —— 配对 new
    //delete[] 数组变量 —— 配对 new[]
    //作用:
    //delete的作用就是释放通过new在堆上分配的动态内存
    #pragma endregion

    #pragma region 知识点 关于delete[]

    //在使用delete[]时,一定要注意
    //它只能释放连续存储的数组
    //一般为用new[]创建的数组



    //举例说明:

    //1.MyClass* arr = new MyClass[5]; 
    //  arr 是指向第一个对象的指针
    //  堆中结构为
    //  +-----------+-----------+-----------+-----------+-----------+
    //  | MyClass 0 | MyClass 1 | MyClass 2 | MyClass 3 | MyClass 4 |
    //  +-----------+-----------+-----------+-----------+-----------+
    //  此时内存是连续的,我们可以用delete[]来进行释放
    MyClass* arr = new MyClass[5];
    delete[] arr;
    arr = nullptr;


    //2.MyClass* arr[5];
    //  arr是一个栈上的 指针数组
    //  是用来存储5个指针对象的数组,其中的元素需要我们手动来new
    //  因此他们是不连续的,不能用delete[]来进行释放,需要遍历数组,单独释放其中的每个元素

    // 创建一个包含5个MyClass指针的数组(一级指针)
    // 注意:这是一个在栈上分配的数组,数组本身的内存会在作用域结束时自动释放
    // 但数组中存储的指针指向的对象是在堆上分配的
    MyClass* arr2[5];

    // 为每个数组元素分配一个MyClass对象(在堆上)
    for (int i = 0; i < 5; i++)
        arr2[i] = new MyClass();

    // 错误示例:不能使用delete[]释放栈上的数组
    // arr2是栈上的数组,其内存会在作用域结束时自动释放
    // 使用delete[]会导致未定义行为(通常是程序崩溃)
    // delete[] arr2;

    // 正确做法:遍历数组,释放每个指针指向的堆上对象
    for (int i = 0; i < 5; i++)
    {
        if (arr2[i] != nullptr)
        {
            // 释放指针指向的MyClass对象(堆内存)
            delete arr2[i];
            // 将指针置空,避免成为野指针
            arr2[i] = nullptr;
        }
    }

    // 当作用域结束时,栈上的数组arr2会自动释放
    // 但此时数组中的所有指针已经被置为nullptr(或初始化为nullptr)



    //3.MyClass** arr = new MyClass*[5];
    // 	arr是一个堆上的 指针数组
    //  arr 是指向第一个对象的指针,但是第一个对象实际上存储的是指针对象,并不是对象
    //  堆中结构为
    //  +----------+----------+----------+----------+----------+
    //  |  arr[0]  |  arr[1]  |  arr[2]  |  arr[3]  |  arr[4]  |
    //  +----------+----------+----------+----------+----------+
    //        ↓          ↓
    //    指向实际 new 出来的 MyClass 对象(或为 nullptr)
    //    MyClass地址  MyClass地址  MyClass地址  MyClass地址  MyClass地址
    //  此时我们不仅需要 delete[] arr
    //  还需要 delete 其中的每个元素

    // 声明一个指向 MyClass 指针的指针数组,在堆上分配能存储 5 个指针的空间
    // 本质:arr3 是一个指针,指向一块连续的内存区域,该区域可存放 5 个 MyClass* 类型的指针
    MyClass** arr3 = new MyClass * [5];

    // 循环为每个指针元素分配实际的 MyClass 对象内存
    for (int i = 0; i < 5; i++) {
        // 为每个指针分配 MyClass 实例的内存,arr3[i] 现在指向堆上的 MyClass 对象
        // 注意:此时形成了 "指针数组指向对象" 的二级内存结构
        arr3[i] = new MyClass();
    }

    // 内存释放阶段:先释放每个指针指向的对象,再释放指针数组本身
    // 为什么先释放对象?因为如果先释放指针数组,会导致 arr3[i] 指针失效,无法再访问对象
    for (int i = 0; i < 5; i++) {
        if (arr3[i] != nullptr) {
            // 释放单个 MyClass 对象的内存,避免内存泄漏
            // delete 会调用对象的析构函数,清理其内部资源
            delete arr3[i];
            // 将指针置为 nullptr,防止成为野指针(后续访问时可通过 nullptr 检查避免崩溃)
            arr3[i] = nullptr;
        }
    }

    // 释放指针数组本身的内存,该内存用于存储 5 个 MyClass* 指针
    // delete[] 会释放 new[] 分配的连续内存,并正确处理数组大小(调用对应次数的析构函数)
    delete[] arr3;
    // 置为 nullptr 确保指针不再指向有效内存,避免误操作
    arr3 = nullptr;

    #pragma endregion

}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏