今天我们来谈谈C++中的new和delete😊😊😊。在软件开发中,常常需要动态地分配和撤销内存空间,C语言中利用库函数malloc和free分配和撤销内存空间的。而在C++中则是 new和delete
- malloc函数时必须指定需要开辟的内存空间的大小,需要做类型强转
- malloc开辟内存失败,返回nullptr
- new 不仅可以做内存开辟(调用构造函数,如果有的话),还可以做内存初始化操作
- new 开辟内存失败会抛出bad_alloc类型的异常
- delete 调用析构函数(如果有的话),再调用operator delete,进行free
# malloc、new的使用格式
int *p = (int*)malloc(sizeof(int)); //malloc
if(p == nullptr) return -1;
free(p);int *p1 = new int(20); //new
delete p1;int *p2 = new int[20]();
delete[] p2;
# 对于new的使用,有多种方式如下:
int *p = new int(20); //普通
int *p2 = new (nothrow) int; //不跑异常
const int *p3 = new const int(40); //常量int data = 2;
int *p4 = new (&data) int(40); //定位new,把指定位置的内存空间对于存储的数据修改
# new 、 delete的底层原理
在new和delete的底层汇编指令上,执行命令时实际上是调用 operator new 和 operator delete 这两个重载函数
# 重写一遍new / []和 delete / []
void* operator new (size_t size)
{void* p = malloc(size); //底层还是通过malloc来开辟内存if (p == nullptr) {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); //底层还是通过malloc来开辟内存if (p == nullptr) {throw bad_alloc();}cout << "operator new[] addr: " << p << endl;return p;
}void operator delete[] (void* ptr)
{cout << "operator delete[] addr: " << ptr << endl;free(ptr);
}int main()
{try{int* p = new int(20);delete p;int* q = new int[10];delete[] q;}catch (const bad_alloc& err) { cerr << err.what() << endl; }return 0;
}
new 和 delete能够混用吗?这里给出一段代码
class Test
{
public:Test(int data = 10){ cout << "Test()" << endl; }~Test() {cout << "~Test()" << endl; }
private:int* ptr;
};int main()
{int* p = new int(20);delete[] p;int* q = new int[10];delete q;Test* pp = new Test();//delete []pp; //混用delete 和 delete[]delete pp;Test* qq = new Test[5];delete[] qq;//delete qq; //混用delete 和 delete[]return 0;
}
我们发现这里对于普通的编译器内置类型,new和delete混用没问题,但是对于对象Test,构造了5次,析构了一次,最后系统崩溃了,why ? ? ? 对于new Test[5]
开辟的不只是5个对象的字节,实际上它多开了4个字节用于存储对象的个数,当我们执行delete
调用operator delete(void* ptr)
时,传入的ptr
其实应该是给第一个对象分配内存的地址 - 4,同理对于delete [] pp
也会往前找4个字节,而它并不是从它前4个字节的内存上开辟的,会出现问题,即new 和 delete 不能混用
简单对象池的实现
#include<iostream>
#include<cstring>
using namespace std;template<typename T>
class Queue
{
public:Queue(){_front = _rear = new QueueItem();}~Queue(){QueueItem* cur = _front;while (cur != nullptr){_front = _front->_next;delete cur;cur = _front;}}void push(const T& val){QueueItem* item = new QueueItem(val);_rear->_next = item;_rear = item;}void pop(){if (empty()){return;}QueueItem* first = _front->_next;_front->_next = first->_next;if (_front->_next == nullptr) _rear = _front;delete first;}T front() const { return _front->_next->_data; }bool empty() const { return _front == _rear; }private:struct QueueItem{QueueItem(T data = T()) :_data(data), _next(nullptr) {}// Memory managementvoid* operator new(size_t size){if (_itemPool == nullptr){_itemPool = (QueueItem*)new (std::nothrow) char[Pool_ITEM_SIZE * sizeof(QueueItem)];QueueItem* p = _itemPool;for (; p < _itemPool + Pool_ITEM_SIZE - 1; p++){p->_next = p + 1;}p->_next = nullptr;}QueueItem* p = _itemPool;_itemPool = _itemPool->_next;return p;}void operator delete(void* ptr){QueueItem* p = static_cast<QueueItem*>(ptr);p->_next = _itemPool;_itemPool = p;}T _data;QueueItem* _next;static const int Pool_ITEM_SIZE = 1000000;static QueueItem* _itemPool;};QueueItem* _front; // HeadQueueItem* _rear; // Tail
};template<typename T>
typename Queue<T>::QueueItem* Queue<T>::QueueItem::_itemPool = nullptr;int main()
{Queue<int> q;for (int i = 0; i < 1000000; i++) {q.push(i);q.pop();}cout << q.empty() << endl;return 0;
}
🌻🌻🌻以上就是浅谈C/C++的new和delete以及对象池的实现的内容,如果聪明的你浏览到这篇文章并觉得文章内容对你有帮助,请不吝动动手指,给博主一个小小的赞和收藏 🌻🌻🌻