内存分配是C++编程中的核心概念,主要分为栈分配 和堆分配两种方式。
1. 栈内存分配(自动分配)
栈内存由编译器自动管理,分配和释放速度快。
特点:
- 自动分配和释放
- 大小有限(通常几MB)
- 局部变量存储在栈上
- 函数结束时自动释放
cpp
#include <iostream>
using namespace std;
void stackExample() {
int x = 10; // 栈上分配
int arr[100]; // 栈上分配数组(大小固定)
double d = 3.14;
// 函数结束时,所有局部变量自动释放
}
int main() {
stackExample();
return 0;
}
2. 堆内存分配(动态分配)
堆内存由程序员手动管理,使用 new 和 delete 操作符。
特点:
- 手动分配和释放
- 内存较大(受系统限制)
- 生命周期由程序员控制
- 分配速度较慢
3. new 和 delete 的基本用法
分配单个变量
cpp
// 分配内存
int *p = new int; // 分配一个int类型的内存
*p = 42; // 向分配的内存写入值
// 分配并初始化
int *p2 = new int(100); // 直接初始化为100
// 释放内存
delete p;
delete p2;
p = nullptr; // 好习惯:释放后置为空指针
p2 = nullptr;
分配数组
cpp
// 分配数组
int size = 10;
int *arr = new int[size]; // 分配10个int的数组
// 初始化数组
for (int i = 0; i < size; i++) {
arr[i] = i * 10;
}
// 释放数组内存(必须使用 delete[])
delete[] arr;
arr = nullptr;
4. new 的高级用法
初始化数组(C++11及以上)
cpp
// 使用初始化列表
int *arr1 = new int[5]{1, 2, 3, 4, 5};
// 默认初始化(所有元素为0)
int *arr2 = new int[5](); // 所有元素初始化为0
// 分配并初始化字符串
char *str = new char[10]{'H', 'e', 'l', 'l', 'o', '\0'};
分配多维数组
cpp
// 方法1:使用一维数组模拟
int rows = 3, cols = 4;
int *matrix = new int[rows * cols];
// 访问元素:matrix[i * cols + j]
// 方法2:指针数组(更直观但需要多层释放)
int **matrix2 = new int*[rows];
for (int i = 0; i < rows; i++) {
matrix2[i] = new int[cols];
}
// 使用
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix2[i][j] = i * j;
}
}
// 释放多维数组
for (int i = 0; i < rows; i++) {
delete[] matrix2[i];
}
delete[] matrix2;
matrix2 = nullptr;
5. 内存分配失败处理
传统方式(抛出异常)
cpp
try {
int *p = new int[1000000000000]; // 分配过大的内存
delete[] p;
} catch (const std::bad_alloc& e) {
cout << "内存分配失败: " << e.what() << endl;
}
使用 std::nothrow(不抛出异常)
cpp
int *p = new(std::nothrow) int[1000000000000];
if (p == nullptr) {
cout << "内存分配失败" << endl;
// 处理错误
} else {
delete[] p;
}
6. 动态分配对象
单个对象
cpp
class MyClass {
public:
int value;
MyClass(int v) : value(v) {
cout << "构造函数: " << value << endl;
}
~MyClass() {
cout << "析构函数: " << value << endl;
}
};
int main() {
// 动态创建对象
MyClass *obj = new MyClass(42);
// 使用对象
cout << "对象值: " << obj->value << endl;
// 手动释放
delete obj;
obj = nullptr;
return 0;
}
7. 内存分配的最佳实践
1. 总是检查分配是否成功
cpp
int *p = new(std::nothrow) int[1000];
if (!p) {
// 处理内存不足的情况
cerr << "内存不足!" << endl;
return -1;
}
2. 配对使用 new/delete 和 new[]/delete[]
cpp
// 正确
int *single = new int;
delete single;
int *array = new int[10];
delete[] array; // 注意是 delete[]
// 错误
int *arr = new int[10];
delete arr; // 错误!应该使用 delete[]
3. 避免内存泄漏
cpp
void badFunction() {
int *p = new int[100];
// 忘记 delete[] p; // 内存泄漏!
}
void goodFunction() {
int *p = new int[100];
// 使用内存...
delete[] p; // 正确释放
p = nullptr;
}
4. 使用 RAII(Resource Acquisition Is Initialization)
cpp
class SmartArray {
private:
int *data;
int size;
public:
SmartArray(int n) : size(n) {
data = new int[n];
}
~SmartArray() {
delete[] data;
data = nullptr;
}
// 禁用拷贝构造和赋值(或实现深拷贝)
SmartArray(const SmartArray&) = delete;
SmartArray& operator=(const SmartArray&) = delete;
// 移动语义
SmartArray(SmartArray&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
};
int main() {
SmartArray arr(100); // 自动管理内存
// 函数结束时自动调用析构函数释放内存
return 0;
}