今天我们来谈谈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 management
void* 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; // Head
QueueItem* _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以及对象池的实现的内容,如果聪明的你浏览到这篇文章并觉得文章内容对你有帮助,请不吝动动手指,给博主一个小小的赞和收藏 🌻🌻🌻