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

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

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

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_ptr 或 std::shared_ptr)来自动管理生命周期,这是现代 C++ 的首选方式。
  3. ‌避免野指针‌:

    • 执行 delete p 后,指针 p 仍然指向原来的地址(即悬空指针)。再次使用 *p 或 delete 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,以从根本上杜绝内存泄漏和悬空指针问题。
相关推荐
别动我齐刘海2 分钟前
实时控制学习2
linux·c++·人工智能·学习·算法
霸道流氓气质14 分钟前
AgentFlow 入门与实战:Task-Based 并发、EWMA 动态调度与四道门禁的 Java 生产级编排
java·开发语言
释厄6231 小时前
错误无误公理——错误正确本同源都迭代定律——逆转有价值
android·开发语言·kotlin
2601_962885721 小时前
如何用 Python计算 CR能量指标(中间意愿指标)?
开发语言·python
hetao17338371 小时前
校内场-提高组 ZYZSC-S-Round 2
c++·算法
hetao17338372 小时前
2026-10-14 hetao1733837 的刷题记录
c++·算法
临床数据科学和人工智能兴趣组2 小时前
在R语言的生态系统中,字符串处理一直是一个重要且复杂的任务
开发语言·正则表达式·r语言·r语言-4.2.1
蜗牛互联网2 小时前
Python调用Gemini Structured Outputs实现工单路由门禁
java·开发语言·人工智能·python
SEO_juper2 小时前
给网页做可引用性评分:判断内容够不够让 AI 引用(GEO 工具,附代码)
开发语言·人工智能·爬虫·python·seo·独立站
Wang's Blog2 小时前
Java 项目实战: 交友项目 - 产品定位、功能模块与客户端原型解读
java·开发语言·交友