异常处理与动态存储空间分配
内存动态分配和释放
-
动态分配:
- 使用
new
分配单个对象,如int* y = new int;
。 - 使用
new[]
分配数组,如int* x = new int[9];
。 - 使用
new
分配二维数组的指针数组和每行的数组,如x = new G* [NumberOfRow];
和x[i] = new G[NumberOfColumns];
。
- 使用
-
内存释放:
- 使用
delete
释放单个对象,如delete y;
。 - 使用
delete[]
释放数组,如delete[] x;
。 - 使用循环释放二维数组的每行,然后释放指针数组,如:
for(int i = 0; i < NumberOfRow; i++) delete[] x[i]; delete[] x;
- 使用
异常处理
-
try
块:将可能抛出异常的代码放入try
块中,如:try { t = new float[n]; }
-
catch
块:捕获并处理异常,如:catch (const std::bad_alloc&) { std::cerr << "Out of memory" << endl; exit(1); }
-
多类型异常处理:可以捕获不同类型的异常,如:
catch (const char* e) { cout << "Caught exception: " << e << endl; } catch (const std::exception& e) { cout << "Caught exception: " << e.what() << endl; } catch (...) { cout << "Caught unknown exception" << endl; }
在C++中,动态建立和删除二维数组需要对内存进行手动管理。下面详细讲解代码中动态建立和删除二维数组的过程。
动态建立二维数组
在代码中,make2dArray
模板函数用于动态分配一个二维数组。以下是这个函数的详细讲解:
template<class G>
bool make2dArray(G** &x, int NumberOfRow, int NumberOfColumns){
try {
// 分配一个包含 NumberOfRow 个元素的指针数组,每个元素都是指向 G 类型的指针
x = new G* [NumberOfRow];
for(int i = 0; i < NumberOfRow; i++) {
// 为每个指针分配一个包含 NumberOfColumns 个 G 类型元素的数组
x[i] = new G [NumberOfColumns];
}
return true; // 如果成功分配,返回 true
} catch (const std::bad_alloc&) {
return false; // 如果内存分配失败,捕获异常并返回 false
}
}
详细步骤:
-
声明指针数组:
x = new G*[NumberOfRow];
这里的
x
是一个指向指针的引用,通过new
操作符动态分配一个包含NumberOfRow
个元素的指针数组。每个元素都是指向G
类型的指针。 -
分配每行的数组:
for(int i = 0; i < NumberOfRow; i++) { x[i] = new G[NumberOfColumns]; }
使用循环遍历指针数组,为每个指针分配一个包含
NumberOfColumns
个G
类型元素的数组。 -
异常处理:
catch (const std::bad_alloc&) { return false; }
如果在分配内存的过程中发生异常(如内存不足),捕获
std::bad_alloc
异常并返回false
。
删除二维数组
在代码中,delete2dArray
模板函数用于释放动态分配的二维数组。以下是这个函数的详细讲解:
template<class G>
void delete2dArray(G** &x, int NumberOfRow){
for(int i = 0; i < NumberOfRow; i++) {
// 释放每行的数组
delete[] x[i];
}
// 释放指针数组
delete[] x;
// 将指针置为 NULL,避免悬空指针
x = NULL;
}
详细步骤:
-
释放每行的数组:
for(int i = 0; i < NumberOfRow; i++) { delete[] x[i]; }
使用循环遍历指针数组,释放每个指针指向的数组内存。
-
释放指针数组:
delete[] x;
释放指针数组本身的内存。
-
防止悬空指针:
x = NULL;
将指针
x
置为NULL
,以避免悬空指针。
在 main
函数中的调用
以下是 main
函数中动态分配和删除二维数组的部分:
int r = 5, c = 5; // 假设初始化 r 和 c 为 5
int** p; // 定义一个指向指针的指针
try {
if (!make2dArray(p, r, c)) { // 动态分配一个 r 行 c 列的二维数组
std::cerr << "cannot make p" << endl; // 输出错误信息
exit(1); // 退出程序
}
} catch (const std::bad_alloc&) { // 捕获内存分配失败的异常
std::cerr << "cannot make p" << endl; // 输出错误信息
exit(1); // 退出程序
}
// 释放动态分配的二维数组的内存
delete2dArray(p, r);
详细步骤:
-
动态分配二维数组:
if (!make2dArray(p, r, c)) { std::cerr << "cannot make p" << endl; exit(1); }
调用
make2dArray
函数为指针p
动态分配一个r
行c
列的二维数组。如果分配失败,输出错误信息并退出程序。 -
释放二维数组内存:
delete2dArray(p, r);
调用
delete2dArray
函数释放指针p
指向的二维数组的内存。
总结
- 动态建立二维数组:使用
new
操作符分配指针数组和每行的数组,并处理内存分配失败的异常。 - 释放二维数组内存:使用
delete[]
操作符释放每行的数组和指针数组,并将指针置为NULL
以防止悬空指针。 - 异常处理:使用
try-catch
块捕获和处理内存分配失败的异常,确保程序在内存不足时能够正确处理并输出错误信息。
代码示例
#include <iostream>
using std::cout;
using std::endl;
// 定义一个模板函数 abc,接受三个相同类型的参数,返回 a + b * c 的结果
template<class T>
T abc(T a, T b, T c){
return a + b * c;
}
// 定义一个模板函数 bcd,接受三个不同类型的参数,返回 a + b * c 的结果
template<class Ta, class Tb, class Tc>
Ta bcd(const Ta& a, const Tb& b, const Tc& c){
return a + b * c;
}
// 定义一个模板函数 make2dArray,动态创建一个二维数组并返回成功与否
template<class G>
bool make2dArray(G** &x, int NumberOfRow, int NumberOfColumns){
try {
x = new G* [NumberOfRow]; // 分配指针数组,每个指针指向一行
for(int i = 0; i < NumberOfRow; i++)
x[i] = new G [NumberOfColumns]; // 分配每行的数组
return true; // 成功分配返回 true
} catch (const std::bad_alloc&) { // 捕获内存分配失败的异常
return false; // 分配失败返回 false
}
}
// 定义一个模板函数 delete2dArray,释放动态分配的二维数组
template<class G>
void delete2dArray(G** &x, int NumberOfRow){
for(int i = 0; i < NumberOfRow; i++)
delete[] x[i]; // 释放每行的内存
delete[] x; // 释放指针数组的内存
x = NULL; // 将指针置为 NULL,避免悬空指针
}
// 定义一个函数 cde,如果参数 <= 0,则抛出异常;否则返回 a + b * c 的结果
int cde(int a, int b, int c){
if(a <= 0 || b <= 0 || c <= 0)
throw "All parameters should be > 0"; // 抛出 const char* 类型的异常
return a + b * c;
}
int main() {
try {
// 调用模板函数 abc,输出结果
cout << abc(1, 2, 3) << endl; // 输出 7
// 调用模板函数 bcd,输出结果
cout << bcd(1, 2.35, 3.10e-2) << endl; // 输出 1.07285
// 调用函数 cde,输出结果(会抛出异常)
cout << cde(-3, 2, 8) << endl;
} catch (const char* e) { // 捕获 const char* 类型的异常
cout << "Caught exception: " << e << endl; // 输出异常信息
} catch (const std::exception& e) { // 捕获 std::exception 类型的异常
cout << "Caught exception: " << e.what() << endl; // 输出异常信息
} catch (...) { // 捕获所有其他类型的异常
cout << "Caught unknown exception" << endl; // 输出未知异常信息
}
try {
// 再次调用函数 cde,输出结果(会抛出异常)
cout << cde(4, 3, -1) << endl;
} catch (const char* e) { // 捕获 const char* 类型的异常
cout << "throw " << e << endl; // 输出异常信息
}
int* y = new int; // 动态分配一个 int 型变量
*y = 10; // 将 y 指向的值设为 10
int* x = new int[9]; // 动态分配一个包含 9 个 int 的数组
cout << y << " " << *y << endl; // 输出 y 的地址和值
cout << x << " " << *x << endl; // 输出 x 的地址和第一个元素的值
delete y; // 释放动态分配的单个 int 变量的内存
delete[] x; // 释放动态分配的 int 数组的内存
int n = 10; // 初始化 n 为 10
float* z = new float[n]; // 动态分配一个包含 n 个 float 的数组
float* t;
try {
t = new float[n]; // 动态分配一个包含 n 个 float 的数组
} catch (const std::bad_alloc&) { // 捕获内存分配失败的异常
std::cerr << "Out of memory" << endl; // 输出错误信息
exit(1); // 退出程序
}
char(*h)[5]; // 定义一个指向包含 5 个 char 的数组的指针
try {
h = new char[n][5]; // 动态分配一个 n 行 5 列的二维 char 数组
} catch (const std::bad_alloc&) { // 捕获内存分配失败的异常
std::cerr << "out of memory" << endl; // 输出错误信息
exit(1); // 退出程序
}
int r = 5, c = 5; // 初始化 r 和 c 为 5
int** p; // 定义一个指向指针的指针
try {
if (!make2dArray(p, r, c)) { // 动态分配一个 r 行 c 列的二维数组
std::cerr << "cannot make p" << endl; // 输出错误信息
exit(1); // 退出程序
}
} catch (const std::bad_alloc&) { // 捕获内存分配失败的异常
std::cerr << "cannot make p" << endl; // 输出错误信息
exit(1); // 退出程序
}
delete2dArray(p, r); // 释放动态分配的二维数组的内存
// 释放 z 和 t
delete[] z; // 释放动态分配的 float 数组 z 的内存
delete[] t; // 释放动态分配的 float 数组 t 的内存
// 释放 h
delete[] h; // 释放动态分配的二维 char 数组 h 的内存
return 0;
}