C++ 内存分配详解

内存分配是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. 堆内存分配(动态分配)

堆内存由程序员手动管理,使用 newdelete 操作符。
特点:

  • 手动分配和释放
  • 内存较大(受系统限制)
  • 生命周期由程序员控制
  • 分配速度较慢

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/deletenew[]/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;
}
相关推荐
名字还没想好☜7 小时前
Python f-string 进阶:数字格式化、对齐填充、调试 = 号与嵌套表达式
开发语言·数据库·python·字符串格式化·f-string
·薯条大王7 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
一壶浊酒..10 小时前
Scrape Webpack练习
开发语言·javascript·webpack
命运之光11 小时前
【C语言完整代码】就诊信息管理系统
java·c语言·开发语言
命运之光11 小时前
【C语言完整代码】图书管理系统:图书馆场景下的增删改查实战
c语言·开发语言
猿长大人11 小时前
C# | Serilog 新手入门
开发语言·c#·.net·log
hansang_IR12 小时前
【题解】LC:倍增 / 区间并查集(Range Parallel Unionfind)
c++·算法·并查集
东东最爱敲键盘12 小时前
day7.c++继承
c++
在世修行13 小时前
从零打造 C# 工业视觉检测系统(七):串口通信 SerialPort 封装与开发
开发语言·c#·modbus rtu·rs232/rs485
沫璃染墨13 小时前
《从零入门Linux系统篇(十五):系统工具篇·六——GDB调试器详解:从程序执行控制到高级调试技巧》
linux·运维·服务器·c语言·c++