C++ -- 动态内存分配和释放(new/delete)

在 C++ 中,newdelete 是用于‌动态内存管理 ‌的核心运算符。它们允许程序在运行时从‌**堆区(Heap/Free Store)**‌申请和释放内存,这与编译时确定大小的栈区内存不同。

以下是 newdelete 的详细用法、核心特性及注意事项。

1. 基本语法与步骤

使用堆区内存通常遵循以下四个步骤:

  1. 声明指针‌:定义一个指向特定类型的指针变量。
  2. 申请内存 ‌:使用 new 运算符向系统申请内存,并将返回的地址赋值给指针。
  3. 使用内存 ‌:通过解引用指针(*ptr)或箭头运算符(ptr->member)访问和操作内存中的数据。
  4. 释放内存 ‌:当不再需要该内存时,使用 delete 运算符释放它,防止内存泄漏。
1.1 单个变量的分配与释放
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    // 1. 声明指针
    int* p = nullptr;

    // 2. 申请内存 (new)
    // 语法: new 数据类型(初始值);
    p = new int(10); // 申请一个 int 大小的内存,并初始化为 10
    
    // 3. 使用内存
    cout << *p << endl; // 输出: 10
    *p = 20;            // 修改值
    cout << *p << endl; // 输出: 20

    // 4. 释放内存 (delete)
    // 语法: delete 指针变量;
    delete p; 
    p = nullptr; // 建议:释放后将指针置空,避免成为野指针

    return 0;
}
1.2 数组的分配与释放

如果需要使用 new 分配数组,必须使用 delete[] 来释放,否则会导致未定义行为(通常表现为内存泄漏或程序崩溃)。

cpp 复制代码
int main() {
    // 1. 申请数组内存
    // 语法: new 数据类型[元素个数];
    int* arr = new int; 

    // 2. 使用数组
    for(int i = 0; i < 5; ++i) {
        arr[i] = i * 10;
    }

    // 3. 释放数组内存
    // 注意:必须使用 delete[],而不是 delete
    delete[] arr; 
    arr = nullptr;

    return 0;
}

2. new/delete 与 malloc/free 的区别

虽然 C 语言的 malloc/free 也能进行动态内存管理,但 C++ 推荐使用 new/delete,主要区别如下:

cpp 复制代码
class Student {
public:
    Student(int age) : m_age(age) {
        cout << "构造函数被调用" << endl;
    }
    ~Student() {
        cout << "析构函数被调用" << endl;
    }
private:
    int m_age;
};

int main() {
    // 使用 new:自动调用构造函数
    Student* s = new Student(18); 
    
    // 使用 delete:自动调用析构函数
    delete s; 
    
    return 0;
}
// 输出:
// 构造函数被调用
// 析构函数被调用

3. 高级用法与注意事项

3.1 内存分配失败的处理

标准的 new 在失败时会抛出异常。如果你希望它在失败时返回 nullptr 而不是抛出异常,可以使用 nothrow 形式:

cpp 复制代码
#include <new> // 需要包含此头文件

int* p = new (std::nothrow) int;
if (p == nullptr) {
    cout << "内存分配失败" << endl;
} else {
    // 使用内存
    delete[] p;
}
3.2 常见错误与最佳实践
  1. 匹配使用‌:

    • new 对应 delete
    • new[] 对应 delete[]
    • 严禁混用 ‌:用 delete 释放 new[] 分配的数组,或用 free 释放 new 分配的内存,都会导致未定义行为。
  2. 避免内存泄漏‌:

    • 确保每一个 new 都有对应的 delete
    • 如果在 new 之后、delete 之前发生了异常或提前返回,内存可能无法释放。建议使用智能指针(如 std::unique_ptrstd::shared_ptr)来自动管理生命周期,这是现代 C++ 的首选方式。
  3. 避免野指针‌:

    • 执行 delete p 后,指针 p 仍然指向原来的地址(即悬空指针)。再次使用 *pdelete p 会导致严重错误。
    • 习惯 ‌:删除后立即将指针赋值为 nullptr (p = nullptr;)。
  4. 不要重复释放‌:

    • 对同一个指针执行两次 delete 是未定义行为。如果指针已置为 nullptr,再次 delete nullptr 是安全的(无操作)。

4. 总结

  • 简单类型 ‌:new int(10) -> delete p
  • 数组类型 ‌:new int -> delete[] p
  • 类对象 ‌:new Class() -> delete p (自动调用构造/析构)
  • 现代 C++ 建议 ‌:尽量使用智能指针(std::unique_ptr, std::shared_ptr)替代裸指针的手动 new/delete,以从根本上杜绝内存泄漏和悬空指针问题。
相关推荐
brycegao3212 小时前
Vue3+Go 全栈项目上线阿里云|从 0 到 1 踩坑全纪录
开发语言·阿里云·golang
ch.ju2 小时前
Java Programming Chapter 4——cite
java·开发语言
优雅格子衫2 小时前
uniapp 拍照相册选取后超级好用的裁剪组件,增加水印完全自定义
开发语言·前端·javascript·uni-app·vue
xcyxiner2 小时前
ubuntu下 cmake初始化脚本 以及 qt依赖
c++·qt
周末也要写八哥2 小时前
Visual C++6.0下载安装流程及PDF学习手册资源
c++·学习·pdf
Vallelonga2 小时前
Rust 中 unsafe 关键字的语义
开发语言·rust
AI砖家2 小时前
前端 JavaScript 异步处理全方案详解:从回调到 Observable
开发语言·前端·javascript
熬夜敲代码的猫2 小时前
AVL树(C++详解版)
数据结构·c++·算法
思麟呀2 小时前
C++工业级日志项目(七)日志器核心
linux·开发语言·c++·windows