和同事讨论问题时候,他说使用内存池,原因是内存池创建的类不能自动调用构造函数和析构函数。

我询问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


posted on 2025-02-13 16:56  轻于飞  阅读(20)  评论(0)    收藏  举报