7.6 动态内存:new 与 delete
内存分区与为什么需要堆
程序运行时的内存大致分成几块:代码区(指令)、数据区(全局/静态变量)、栈区(stack,存放局部变量,由编译器自动分配和释放)、堆区(heap,由程序员手动分配和释放)。
栈上的局部数组在函数返回后就被释放了,所以不能把它的地址返回给调用者。另外,数组一旦声明,容量就固定了。当数组大小要在运行时才决定,或数据需要在函数返回后继续存在时,就需要在堆上动态申请内存。
new 与 delete
在 C++ 中,new 在堆上申请对象并返回带类型的指针。new[] 申请数组。用完后,单个对象用 delete 释放,数组用 delete[] 释放,否则会造成内存泄漏(memory leak)。
cpp
int *arr = new int[n];
// ... 使用 arr ...
delete[] arr; // 用完释放如果希望申请失败时返回 nullptr,而不是抛出异常,可以使用 std::nothrow。
cpp
#include <new>
int *arr = new (std::nothrow) int[n];
if (arr == nullptr) {
return 1; // 申请失败
}初始化与调整大小
new int[n] 不会把每个元素初始化成确定值。new int[n]() 会对元素做值初始化,所以整数会变成 0。
cpp
int *arr = new int[n](); // 全部为 0用 new[] 申请的原始数组不能直接调整大小。如果要手动扩容,需要申请新数组,复制旧值,释放旧数组,再保存新指针。
cpp
int *next = new int[new_size];
for (int i = 0; i < old_size; i++) {
next[i] = arr[i];
}
delete[] arr;
arr = next;下面的函数在堆上生成斐波那契数列并返回,由调用者在用完后负责 delete[]:
cpp
int *generate_fibonacci(int n) {
int *arr = new (std::nothrow) int[n];
if (arr == nullptr) {
return nullptr;
}
arr[0] = 1;
arr[1] = 1;
for (int i = 2; i < n; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
return arr;
}使用动态内存时要格外谨慎:使用 std::nothrow 时检查 nullptr、避免越界、避免重复释放、delete 之后不要再使用旧指针。
正在加载交互实验...
正在加载概念检查...
正在加载本节练习...
正在加载本节练习...