I have a custom allocator written in C that works without problem. I tried to insert it in a c++ project and I is working with std containers as long as the container is not global or in a class. because the allocator needs to be initialized before any used
Init_allocator(maxPageSize);
int * p = Allocate(sizeof(int) * 100);
Free(p);
Clear_allocator();
Let me show the C++ part:
template<typename T>
struct MyAllocator
{
typedef T value_type;
MyAllocator() = default;
template<typename U>
constexpr MyAllocator(const MyAllocator<U>&) noexcept {}
[[nodiscard]] T * allocate(std::size_t n)
{
if(n > std::numeric_limits<std::size_t>::max() / sizeof(T))
{
throw std::bad_array_new_length();
}
return static_cast<T*>(Allocate(sizeof(T) * n));
}
void deallocate(T * p, std::size_t n) noexcept
{
Free((void *)p);
}
};
template<typename T>
using UnorderedMap = std::unordered_map<T, U, std::hash<T>, std::equal_to<T>,MyAllocator<std::pair<T, U>>>;
So if I use it inside a function there is no problem
main(){
Init_allocator(maxPageSize);
UnorderedMap<std::string, int> myMap;
myMap["one"] = 1;
Clear_allocator();
}
but when I do
class A{
public:
UnorderedMap<std::string, int> mMap;
};
main(){
Init_allocator(maxPageSize);
A myClass;
Clear_allocator();
}
then it crashed and the crash is in the function allocate. I understand that the function been called before the call of Init_allocator so some variable have dirty values. It seems like the class is initialized before. This is where I am lost. My init will call the malloc and create different pages and than Allocate is just a free list. Is there a solution or do I have to give up on this allocator?
EDIT: adding the allocator code and pointing where it crashed
void * Allocate(size_t size, size_t alignment, size_t id, const char * file, int line)
{
if(alignment == 0)
{
alignment = gDefaultAlignment;
}
AllocationGroup * grp = &gAllocGrp[id];
MemoryPage * page = NULL;
size_t alignShift = alignment < 2 ? 0 : alignment * 2;
size_t size_ = MIN_META_SIZE - 1 + size + alignShift;
if(size_ >= grp->pageSize) //CRASH HERE with Exception has orrured Exception 0xc00000005 encountered at adress xxxx: Accesss violation reading loacation xxxx
{
LOGC(eFATAL, gTag, gTagColor, "Cannot allocat that much");
}
LockMutex(&grp->mutex);
size_t pageCount = grp->pageCount;
UnlockMutex(&grp->mutex);
for(size_t i = 0; i < pageCount; ++i)
{
LockMutex(&grp->pages[i].mutex);
size_t bigestFree = grp->pages[i].bigestFree;
UnlockMutex(&grp->pages[i].mutex);
if(bigestFree >= size_)
{
page = &grp->pages[i];
break;
}
}
if(page == NULL)
{
if(pageCount < MAX_PAGES)
{
createPage(grp);
page = &grp->pages[grp->pageCount - 1];
}
else
{
LOGC(eFATAL, gTag, gTagColor, "Out of Memory!");
}
}
void * result = AllocateFromPage(page, size_, alignment, file, line);
struct BlockHeader * bH = getBlockHeader(result);
bH->payloadSize = size;
return result;
}
I will add that it doesn't not crash with std::vector, unordered_set and string. only unordered_map crashed.
Edit 2: I dont' really understand what even the code is relevant, I think it is more theorical than a bug. I wrote this in allocate to test
void * Allocate(...)
{
fprintf(stderr, "Allocator called\n");
return;
}
And it showed that the allocator is called before main() meaning even if there is not bug or there is a bug it doesnt matter as Allocate is called before initialization. then added in allocate
void * Allocate(...)
{
if(global_initialize == 0)
{
InitAllocator(/*init with default values*/);
}
...
}
after that it worked but now Clear_allocator(); is a new issue as the destructor of std::unordered_map will call Free() after main() which already call Clear_allocator();