new/delete 重载与对象池实现
C++ 内存管理笔记:new/delete 重载与对象池实现
一、new/delete 基础概念
1. malloc 与 new 的区别
- 内存分配方式
malloc
按字节分配内存,返回void*
类型new
根据类型分配内存,如new int[10]
返回int*
- 初始化功能
malloc
仅分配内存new
分配内存后调用构造函数初始化对象
- 错误处理
malloc
失败返回nullptr
new
失败抛出bad_alloc
异常
2. free 与 delete 的区别
delete
先调用对象析构函数,再释放内存delete[]
用于释放数组内存,会逐个调用数组元素的析构函数
二、new/delete 重载实现
全局重载示例
// 单个对象内存分配
void* operator new(size_t size) {void* p = malloc(size);if (!p) throw bad_alloc();cout << "operator new addr:" << p << endl;return p;
}// 单个对象内存释放
void operator delete(void* ptr) {cout << "operator delete addr:" << ptr << endl;free(ptr);
}// 数组内存分配
void* operator new[](size_t size) {void* p = malloc(size);if (!p) throw bad_alloc();cout << "operator new[] addr:" << p << endl;return p;
}// 数组内存释放
void operator delete[](void* ptr) {cout << "operator delete[] addr:" << ptr << endl;free(ptr);
}
三、自定义类内存管理
示例类 Test
class Test {
public:Test(int data = 10) : ptr(new int(data)) { cout << "Test()" << endl; }~Test() { delete ptr;cout << "~Test()" << endl; }
private:int* ptr;
};
内存分配与释放测试
// 正确使用方式
Test* p1 = new Test(); // 调用构造函数
delete p1; // 调用析构函数// 错误示例(勿混用)
Test* p2 = new Test[5];
delete p2; // 仅释放首元素,内存泄漏!
delete[] p2; // 正确释放数组
四、对象池实现原理
核心思想
- 预分配大块内存,避免频繁调用
malloc/free
- 通过内存复用提高性能
模板类 Queue 实现对象池
template<typename T>
class Queue {
private:struct QueueItem {QueueItem(T data = T()) : _data(data), _next(nullptr) {}// 对象池内存管理void* operator new(size_t size) {if (_itemPool == nullptr) {// 创建对象池_itemPool = (QueueItem*)new char[POOL_ITEM_SIZE * sizeof(QueueItem)];QueueItem* p = _itemPool;for (; p < _itemPool + POOL_ITEM_SIZE; p++) {p->_next = p + 1; // 构建链表}p->_next = nullptr;}QueueItem* p = _itemPool;_itemPool = _itemPool->_next; // 从池中取出对象return p;}void operator delete(void* ptr) {QueueItem* p = (QueueItem*)ptr;p->_next = _itemPool; // 将对象放回池中_itemPool = p;}T _data;QueueItem* _next;static QueueItem* _itemPool;static const int POOL_ITEM_SIZE = 100000;};QueueItem* _front; // 队头指针QueueItem* _rear; // 队尾指针
};// 静态成员初始化
template<typename T>
typename Queue<T>::QueueItem* Queue<T>::QueueItem::_itemPool = nullptr;
五、对象池性能测试
int main() {Queue<int> que;for (int i = 0; i < 1000000; i++) {que.push(i); // 使用对象池分配内存que.pop(); // 归还内存到对象池}cout << que.empty() << endl;return 0;
}
六、关键要点总结
- 内存泄漏检测
- 可通过重载
new/delete
记录内存分配情况 - 建立全局映射表跟踪未释放的内存
- 可通过重载
- 混用风险
- 对有析构函数的类,
new
与delete
、new[]
与delete[]
必须配对使用 - 内置类型无析构函数,混用不会导致内存泄漏
- 对有析构函数的类,
- 对象池优势
- 减少系统调用开销,提高内存分配效率
- 适合频繁创建和销毁对象的场景
- 内存管理最佳实践
- 优先使用智能指针(如
std::unique_ptr
、std::shared_ptr
) - 仅在性能敏感场景手动管理内存
- 始终保持
new/delete
操作符使用一致性
- 优先使用智能指针(如