跳转到内容

C++ 动态内存分配

来自代码酷

C++动态内存分配[编辑 | 编辑源代码]

动态内存分配是C++中一种在程序运行时(而非编译时)请求和释放内存的机制。它允许程序根据需要灵活地管理内存,特别适合处理未知大小的数据结构或需要长时间保留的数据。

基本概念[编辑 | 编辑源代码]

在C++中,动态内存分配主要通过newdelete运算符实现:

  • new:在堆(heap)上分配内存并返回指向该内存的指针
  • delete:释放先前通过new分配的内存

与静态内存分配的区别[编辑 | 编辑源代码]

特性 静态内存分配 动态内存分配
分配时间 编译时 运行时
内存来源 栈(Stack) 堆(Heap)
大小 固定 可变
生命周期 作用域内 直到显式释放

基本用法[编辑 | 编辑源代码]

单个对象的分配与释放[编辑 | 编辑源代码]

// 分配一个int类型的内存
int* ptr = new int;

// 赋值
*ptr = 42;

// 使用
std::cout << "Value: " << *ptr << std::endl;

// 释放内存
delete ptr;
ptr = nullptr;  // 避免悬空指针

输出

Value: 42

数组的分配与释放[编辑 | 编辑源代码]

// 分配包含5个int的数组
int* arr = new int[5];

// 初始化数组
for (int i = 0; i < 5; ++i) {
    arr[i] = i * 10;
}

// 使用数组
for (int i = 0; i < 5; ++i) {
    std::cout << arr[i] << " ";
}

// 释放数组内存
delete[] arr;
arr = nullptr;

输出

0 10 20 30 40

内存管理图例[编辑 | 编辑源代码]

graph LR A[程序] --> B[栈内存 Stack] A --> C[堆内存 Heap] B --> D[自动管理] C --> E[手动管理 new/delete]

常见问题与最佳实践[编辑 | 编辑源代码]

内存泄漏[编辑 | 编辑源代码]

忘记释放动态分配的内存会导致内存泄漏:

void leakMemory() {
    int* ptr = new int(100);  // 内存泄漏 - 没有对应的delete
}

解决方案

  • 使用智能指针(C++11及以上)
  • 遵循RAII(资源获取即初始化)原则

悬空指针[编辑 | 编辑源代码]

访问已释放的内存:

int* ptr = new int(50);
delete ptr;
*ptr = 60;  // 未定义行为 - ptr现在是悬空指针

解决方案

  • 释放后立即将指针设为nullptr
  • 使用智能指针

智能指针(C++11及以上)[编辑 | 编辑源代码]

现代C++推荐使用智能指针自动管理内存:

#include <memory>

void safeMemory() {
    std::unique_ptr<int> ptr = std::make_unique<int>(42);
    // 不需要手动delete - 超出作用域时自动释放
    std::cout << *ptr << std::endl;
}

实际应用案例[编辑 | 编辑源代码]

动态数据结构[编辑 | 编辑源代码]

动态内存分配在实现链表、树等数据结构时必不可少:

struct Node {
    int data;
    Node* next;
};

Node* createList(int size) {
    Node* head = nullptr;
    Node** current = &head;
    
    for (int i = 0; i < size; ++i) {
        *current = new Node{i, nullptr};
        current = &((*current)->next);
    }
    
    return head;
}

void deleteList(Node* head) {
    while (head != nullptr) {
        Node* temp = head;
        head = head->next;
        delete temp;
    }
}

大型数据处理[编辑 | 编辑源代码]

处理未知大小的数据集:

double* readDataFromFile(const std::string& filename, int& count) {
    std::ifstream file(filename);
    std::vector<double> temp;
    double value;
    
    while (file >> value) {
        temp.push_back(value);
    }
    
    count = temp.size();
    double* data = new double[count];
    std::copy(temp.begin(), temp.end(), data);
    
    return data;
}

数学表达[编辑 | 编辑源代码]

动态内存分配的内存消耗可以表示为: Mtotal=i=1n(Si+Ooverhead) 其中:

  • Mtotal是总内存消耗
  • Si是第i次分配的大小
  • Ooverhead是内存分配器的开销

性能考虑[编辑 | 编辑源代码]

动态内存分配比栈分配慢,因为:

  • 需要查找合适的空闲内存块
  • 可能触发操作系统调用
  • 可能导致内存碎片

优化建议

  • 预分配大块内存
  • 使用内存池
  • 尽可能重用已分配的内存

总结表[编辑 | 编辑源代码]

操作 语法 说明
单个对象分配 new Type 分配单个对象
数组分配 new Type[size] 分配数组
单个对象释放 delete ptr 释放单个对象
数组释放 delete[] arr 释放数组
初始化分配 new Type(value) 分配并初始化