和同事讨论问题时候,他说使用内存池,原因是内存池创建的类不能自动调用构造函数和析构函数。
我询问AI,结论是不能,需要手动调用,给的代码如下:
#include <iostream>
#include <cassert>
#include <vector>
class MemoryPool {
public:
MemoryPool(size_t blockSize, size_t blockCount)
: m_blockSize(blockSize), m_blockCount(blockCount) {
m_pool = new char[blockSize * blockCount];
m_freeList.reserve(blockCount);
// 将每个内存块的地址加入空闲链表
for (size_t i = 0; i < blockCount; ++i) {
m_freeList.push_back(m_pool + i * blockSize);
}
}
~MemoryPool() {
delete[] m_pool;
}
// 从内存池中分配一个内存块
void* allocate() {
if (m_freeList.empty()) {
return nullptr; // 如果没有空闲块了,返回nullptr
}
void* ptr = m_freeList.back();
m_freeList.pop_back();
return ptr;
}
// 释放一个内存块
void deallocate(void* ptr) {
m_freeList.push_back(ptr);
}
private:
char* m_pool; // 内存池的原始内存块
size_t m_blockSize; // 每个内存块的大小
size_t m_blockCount; // 内存池中内存块的数量
std::vector<void*> m_freeList; // 空闲内存块链表
};
class MyClass {
public:
MyClass(int val) : m_val(val) {
std::cout << "MyClass constructor: " << m_val << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor: " << m_val << std::endl;
}
void show() {
std::cout << "Value: " << m_val << std::endl;
}
private:
int m_val;
};
int main() {
// 创建内存池,每个内存块大小足够存放 MyClass 对象,假设我们分配 10 个 MyClass 对象
MemoryPool pool(sizeof(MyClass), 10);
// 分配内存给 MyClass 对象
void* rawMemory = pool.allocate();
if (rawMemory != nullptr) {
// 使用 placement new 在内存池分配的内存上构造 MyClass 对象
MyClass* obj = new (rawMemory) MyClass(42);
// 使用对象
obj->show();
// 手动调用析构函数
obj->~MyClass();
// 将内存块归还给内存池
pool.deallocate(rawMemory);
}
return 0;
}
这里
// 手动调用析构函数
obj->~MyClass();
就手动调用析构函数。
但是就正常的流程来说,new obj,那么一定要delete obj,那么析构函数就将被自动调用。
那么
obj->~MyClass();-》(修改为)delete obj;是否对呢
调用delete它将把归还给堆内存,但是obj不是直接从堆上获取的内存,而是从内存池里获取的,当调用delete后,析构函数会执行,归还空间将会报错:unknown signle
所以上面实例不能自动调用析构函数,而是不能调用析构函数,否则就会报错。
如果一定要自动调用,那么应该怎么写呢?
class MyClass {
public:
MyClass(int val) : m_val(val) {
std::cout << "MyClass constructor: " << m_val << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor: " << m_val << std::endl;
}
void show() {
std::cout << "Value: " << m_val << std::endl;
}
void* operator new(size_t size, MemoryPool * pool)
{
void* ptr = pool->allocate();
if(NULL != ptr)
{
memset(ptr,0,size);
return ptr;
}
return NULL;
}
void operator delete(void* ptr)
{
//什么都不做
}
private:
int m_val;
};
int main() {
// 创建内存池,每个内存块大小足够存放 MyClass 对象,假设我们分配 10 个 MyClass 对象
MemoryPool pool(sizeof(MyClass), 10);
MyClass* obj = new (&pool) MyClass(42);
// 使用对象
obj->show();
// 手动调用析构函数
// obj->~MyClass();
//自动调用析构函数
delete obj;
//回收内存
pool.deallocate(obj);
return 0;
}
这样就能自动调用析构函数了。
但是这里有个问题,内存需要我自己显示的回收。
我都能够通过new 来调用内存池分配内存,同样也可以delete调用内存池回收内存。
写法如下:
#include <iostream>
#include <cassert>
#include <vector>
#include <string.h>
class MemoryPool {
public:
MemoryPool(size_t blockSize, size_t blockCount)
: m_blockSize(blockSize), m_blockCount(blockCount) {
m_pool = new char[blockSize * blockCount];
m_freeList.reserve(blockCount);
// 将每个内存块的地址加入空闲链表
for (size_t i = 0; i < blockCount; ++i) {
m_freeList.push_back(m_pool + i * blockSize);
}
}
~MemoryPool() {
delete[] m_pool;
}
// 从内存池中分配一个内存块
void* allocate() {
if (m_freeList.empty()) {
return nullptr; // 如果没有空闲块了,返回nullptr
}
void* ptr = m_freeList.back();
m_freeList.pop_back();
return ptr;
}
// 释放一个内存块
void deallocate(void* ptr) {
m_freeList.push_back(ptr);
}
private:
char* m_pool; // 内存池的原始内存块
size_t m_blockSize; // 每个内存块的大小
size_t m_blockCount; // 内存池中内存块的数量
std::vector<void*> m_freeList; // 空闲内存块链表
};
class MyClass {
public:
MyClass(int val) : m_val(val) {
std::cout << "MyClass constructor: " << m_val << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor: " << m_val << std::endl;
}
void show() {
std::cout << "Value: " << m_val << std::endl;
}
void* operator new(size_t size, MemoryPool * pool)
{
void* ptr = pool->allocate();
if(NULL != ptr)
{
memset(ptr,0,size);
return ptr;
}
return NULL;
}
void operator delete(void* ptr,MemoryPool * pool)
{
((MyClass*)ptr)->~MyClass() ;
pool->deallocate(ptr);
}
private:
int m_val;
};
int main() {
// 创建内存池,每个内存块大小足够存放 MyClass 对象,假设我们分配 10 个 MyClass 对象
MemoryPool pool(sizeof(MyClass), 10);
MyClass* obj = new (&pool) MyClass(42);
// 使用对象
obj->show();
// 手动调用析构函数
// obj->~MyClass();
MyClass::operator delete( obj,&pool );
return 0;
}
其实
MyClass::operator delete( obj,&pool ); 这样写了后析构函数还是需要显示调用,为了实现delete 效果,我在delete重载中显示调用了
其实这样破坏了class的结构。
结论:可以自动调用,但是需要重载类的delete
浙公网安备 33010602011771号