My memory allocator is initialized when overloaded new operator is called:
MyAllocator* GetAllocator()
{
static MyAllocator allocator;
return &allocator;
}
void* operator new(size_t size)
{
return GetAllocator()->Allocate(size);
}
When allocator is constructed, it creates logger. On destructing, it prints out all memory leaks.
MyAllocator::MyAllocator()
{
m_Logger = Logger::Create("Allocator.log");
m_Logger->Writef("...");
}
MyAllocator::~MyAllocator()
{
m_Logger->Writef("%u Leak(s) Total", m_LeakCount);
}
Because Logger::Writef uses local static buffer, I need static mutex.
Logger::Writef(const char* fmt, ...)
{
static char buffer[4096];
static Mutex mutex;
mutex.Lock();
...
}
With this, we get following initialization order:
- GetAllocator::allocator
- Logger::Writef::mutex
Order of destruction is opposite, which gives us:
- Logger::Writef::mutex
- GetAllocator::allocator
And here's the deal, at point when Logger::Writef is called from destructor of MyAllocator, Logger::Writef::mutex is already destructed.
Your problem is simple. It's caused by the order of destruction, so all you have to do is change the order of destruction.
As you noted the order of destruction is opposite to the order of construction. So you need to make sure your logger variables are constructed before your allocator.
You can do this by moving your static logger variables out of function scope and putting them at module scope. They will be constructed at program startup. By putting them inside an anonymous namespace they won't be exposed to other modules.