4

我正在处理内存池/内存分配器实现,我在一个只有特殊的“Client”对象类型可以从池。客户端可以直接构建到池中,也可以使用池进行动态内存调用,或者理论上可以同时使用这两者。 我希望能够超载运营商新运营商删除以一种方式,将调用我的池“alloc()”和“free()”功能,以获得对象所需的内存来构造根据。使用operator new和operator delete自定义内存池/分配器

我遇到的一个主要问题是让我的操作员删除通过调用我写的pool-> free()函数来释放内存。我想出了一个通过将池传入构造函数并使析构函数执行取消分配工作来解决此问题的方法。这是一切都很好,直到有人需要从这个类继承,并根据自己的需要重写析构函数,然后忘记执行内存释放。这就是为什么我想把它全部包装在操作符中,所以功能被隐藏并默认继承。

我的代码是在GitHub上的位置:https://github.com/zyvitski/Pool

的客户我的类定义如下:

class Client 
{ 
public: 
    Client(); 
    Client(Pool* pool); 
    ~Client(); 

    void* operator new(size_t size,Pool* pool); 
    void operator delete(void* memory); 

    Pool* m_pPool; 
}; 

和实现是:

Client::Client() 
{ 

} 
Client::Client(Pool* pool) 
{ 
    m_pPool = pool; 
} 
Client::~Client() 
{ 
    void* p = (void*)this; 
    m_pPool->Free(&p); 
    m_pPool=nullptr; 
} 
void* Client::operator new(size_t size, Pool* pool) 
{ 
    if (pool!=nullptr) { 
     //use pool allocator 
     MemoryBlock** memory=nullptr; 
     memory = pool->Alloc(size); 
     return *memory; 
    } 
    else throw new std::bad_alloc; 
} 
void Client::operator delete(void* memory) 
{ 
    //should somehow free up the memory back to the pool 
    // the proper call will be: 
    //pool->free(memory); 
    //where memory is the address that the pool returned in operator new 

} 

这里是例如主(),我现在使用的是:

int main(int argc, const char * argv[]){ 
    Pool* pool = new Pool(); 
    Client* c = new(pool) Client(pool); 
    /* 
    I'm using a parameter within operator new to pass the pool in for use and i'm also passing the pool as a constructor parameter so i can free up the memory in the destructor 
    */ 

    delete c; 
    delete pool; 
    return 0; 
} 

到目前为止,我的代码工作,但我想知道是否有更好的方法来实现这一目标? 请让我知道,如果我所要求/做的任何事情根本不可能,不好的做法或只是简单的愚蠢。我现在正在使用MacBook Pro,但如果可能的话,我想保留我的代码跨平台。

如果您有任何问题可以帮助您,请告诉我。

当然,感谢任何人谁可以提供帮助。

回答

4

你可能只是返回的内存地址

#include <iostream> 
#include <type_traits> 

class Pool { 
public: 
    static void* Alloc(std::size_t size) { return data; } 
    static void Dealloc(void*) {} 
private: 
    static char data[1024]; 
}; 
char Pool::data[1024]; 


class Client 
{ 
public: 
    void* operator new(size_t size, Pool& pool); 
    void operator delete(void* memory); 
}; 


struct MemoryHeader { 
    Pool* pool; 
}; 


void* Client::operator new(size_t size, Pool& pool) 
{ 
    auto header = static_cast<MemoryHeader*>(pool.Alloc(sizeof(MemoryHeader) + size)); 
    std::cout << " New Header: " << header << '\n'; 
    header->pool = &pool; 
    return header + 1; 
} 

void Client::operator delete(void* memory) 
{ 
    auto header = static_cast<MemoryHeader*>(memory) - 1; 
    std::cout << " Delete Header: " << header << '\n'; 
    header->pool->Dealloc(header); 
} 

int main() 
{ 
    Pool pool; 
    Client* p = new(pool) Client; 
    std::cout << "Client Pointer: " << p << '\n'; 
    delete p; 
    return 0; 
} 
+0

到目前为止我很喜欢这个答案。我看到你在发布后大约一个小时就编辑过它?我很好奇你为什么改变了,为什么改变。我记得有一些字节对齐的东西,你正在使用一个工会的东西。如果你不介意解释我很好奇你在那里做什么,为什么? –

+1

@ArlexZywicki对齐存储是无用的(这里不需要C++ 11的东西,我也在学习) –

0

如果您delete操作者只需调用free,你自定义的分配器不会做电子商务很好的工作之前存储更多的信息。自定义分配器的想法是,它可以与预定义的内存区域一起工作,它可以控制它:当它分配内存时,它将从内存区域或池中释放内存,释放内存时,分配器会“通知”它可以重用该内存。 现在,如果您使用免费的,您只需将内存返回到堆,而不是您的内存池。这部分通常的做法是使用智能指针 - 跟踪可用的内存。

只要您可以跟踪哪些地址正在使用以及哪些地址可用,就可以使用其他任何机制。

希望这有助于

+0

谢谢。我的pool-> free()不会调用常规的free()函数,它基本上就是你所说的。你可以看一下,如果你去拉的git库我发布了一个链接。我不想把这些代码放在问题中,因为它比较笨重,而不是我的问题是直接的。 –

1

随着Dieter Lücking帮助,我能弄清楚如何使用我的游泳池中运营商新运营商删除

这里是运营商新代码:

void* ObjectBase::operator new(size_t size, Pool* pool) 
{ 
    if (pool!=nullptr) { 
     //use pool allocation 
     MemoryBlock** block = pool->Alloc(size+(sizeof(MemoryHeader))); 
     MemoryBlock* t = * block; 
     t = (MemoryBlock*)((unsigned char*)t+sizeof(MemoryHeader)); 
     MemoryHeader* header = new(*block)MemoryHeader(pool); 
     header=nullptr; 
     return t; 
    } 
    else{ 
     //use std allocation 
     void* temp = ::operator new(size); 
     if (temp!=nullptr) { 
      return temp; 
     } 
     else throw new std::bad_alloc; 
    } 
} 

这里是代码为操作或删除

void ObjectBase::operator delete(void* memory) 
{ 
    MemoryBlock* temp = (MemoryBlock*)((unsigned char*)memory-sizeof(MemoryHeader)); 
    MemoryHeader* header = static_cast<MemoryHeader*>(temp); 
    if (header->pool!=nullptr) { 
     if (header->pool->Free((MemoryBlock**)&header)); 
     else 
     { 
      ::operator delete(memory); 
     } 
    } 
    else{ 
     ::operator delete(memory); 
    } 
} 

我使用的建议,“内存头”的想法。

如果由于某种原因导致池发生故障,代码也会以默认使用标准内存分配调用的方式进行设置。

再次感谢您的帮助。

相关问题