C++ 动态内存分配
外观
C++动态内存分配[编辑 | 编辑源代码]
动态内存分配是C++中一种在程序运行时(而非编译时)请求和释放内存的机制。它允许程序根据需要灵活地管理内存,特别适合处理未知大小的数据结构或需要长时间保留的数据。
基本概念[编辑 | 编辑源代码]
在C++中,动态内存分配主要通过new
和delete
运算符实现:
- 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
内存管理图例[编辑 | 编辑源代码]
常见问题与最佳实践[编辑 | 编辑源代码]
内存泄漏[编辑 | 编辑源代码]
忘记释放动态分配的内存会导致内存泄漏:
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;
}
数学表达[编辑 | 编辑源代码]
动态内存分配的内存消耗可以表示为: 其中:
- 是总内存消耗
- 是第i次分配的大小
- 是内存分配器的开销
性能考虑[编辑 | 编辑源代码]
动态内存分配比栈分配慢,因为:
- 需要查找合适的空闲内存块
- 可能触发操作系统调用
- 可能导致内存碎片
优化建议:
- 预分配大块内存
- 使用内存池
- 尽可能重用已分配的内存
总结表[编辑 | 编辑源代码]
操作 | 语法 | 说明 |
---|---|---|
单个对象分配 | new Type |
分配单个对象 |
数组分配 | new Type[size] |
分配数组 |
单个对象释放 | delete ptr |
释放单个对象 |
数组释放 | delete[] arr |
释放数组 |
初始化分配 | new Type(value) |
分配并初始化 |