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