I have just (re)started working on an engine. I'm currently writting the logging system, but it has an error I cant find, so I thought I'ld post the problem here.
My logging system currently consists of an interface, ILog and a factory class, LogFactory. LogFactory inherits from FactoryBase<ILog> and Singleton<LogFactory>, I haven't used multiple inheritance much before so I don't know if that is the problem.
My singleton class, looks like this:
template<typename T>
class Singleton
{
public:
~Singleton();
static T* Instance();
protected:
Singleton();
Singleton(const Singleton& p_Copy);
Singleton& operator=(const Singleton<T>& p_RHS);
};
// Definition
template<typename T>
Singleton<T>::Singleton()
{
}
template<typename T>
Singleton<T>::~Singleton()
{
}
template<typename T>
Singleton<T>::Singleton(const Singleton&)
{
}
template<typename T>
Singleton<T>& Singleton<T>::operator=(const Singleton<T>&)
{
assert(!"Don't call this function");
// Shouldn't be called, therefore output doesn't matter.
return (*this);
}
template<typename T>
T* Singleton<T>::Instance()
{
static T ObjectInstance;
return &ObjectInstance;
}
My ILog class looks like this:
// M3DBASE_EXPORT is a #define for either __declspec(dllexport) or
// __declspec(dllimport)
class M3DBASE_EXPORT ILog
{
public:
ILog();
virtual ~ILog();
virtual void Write(
const String& p_Message,
const String& p_File,
UInt32 p_Line) = 0;
virtual void Write(
const String& p_Message) = 0;
virtual ILog* Clone() = 0;
};
My FactoryBase class looks like this:
template<typename TBase>
class FactoryBase
{
public:
FactoryBase();
virtual ~FactoryBase();
template<typename T>
void RegisterType(const String& p_Identifier)
{
assert(m_RegisteredTypes.end() == m_RegisteredTypes.find(p_Identifier));
m_RegisteredTypes[p_Identifier] = new T;
return;
}
TBase* Create(const String&);
private:
typedef std::map<String,TBase*> MapType;
typedef std::list<TBase*> ListType;
MapType m_RegisteredTypes;
ListType m_CreatedObjects;
};
// Definition
template<typename TBase>
FactoryBase<TBase>::FactoryBase()
{
return;
}
template<typename TBase>
FactoryBase<TBase>::~FactoryBase()
{
// Destroy the prototypes
for(MapType::iterator iter = m_RegisteredTypes.begin();
m_RegisteredTypes.end() != iter;
++iter)
{
delete iter->second;
}
// Destroy the created objects
for(ListType::iterator iter = m_CreatedObjects.begin();
m_CreatedObjects.end() != iter;
++iter)
{
delete (*iter);
}
return;
}
template<typename TBase>
TBase* FactoryBase<TBase>::Create(const String& p_Identifier)
{
assert(m_RegisteredTypes.end() != m_RegisteredTypes.find(p_Identifier));
TBase* Return = m_RegisteredTypes[p_Identifier]->Clone();
m_CreatedObjects.push_back(Return);
return Return;
}
My LogFactory class looks like this:
class M3DBASE_EXPORT LogFactory : public Singleton< LogFactory >,public FactoryBase<ILog>
{
public:
LogFactory(){}
virtual ~LogFactory(){}
};
I written the following test:
int main()
{
try
{
LogFactory::Instance()->RegisterType<ConsoleLog>( _T("ConsoleLog") );
return 0;
}
catch(...)
{
std::cout << "Exception caught." << std::endl;
std::cin.get();
return 1;
}
}
The problem is that AFTER main have returned 0 an exception is thrown, I know that my singleton generates a:
"static LogFactory ObjectInstance;"
And the destructor of this object is called after main, the weird thing is that first after both LogFactory and FactoryBase's destructor have exitted the exception is thrown.
Looking at the callstack I can see that it chrashes in std::map's destructor, when std::map is trying to delete a memory address, that memory address is the address of the ConsoleLog which were registered on the second line of main. Actually I thought I'ld have to delete this myself, but for some reason std::map tries to delete it and throws an exception in _CrtIsValidHeapPointer.
I thought it threw the exception because I also tried to delete that memory, but even though I comment out all my delete statements it fails in that delete call. I also tried to ".clear()" the std::map before exitting the destructor, but for some reason it still knows the memory address of the ConsoleLog.
I believe the error have something to do with using a DLL, because I tried to copy-paste some of the code to a single main.cpp file and here it works fine. The source which works fine is this:
#include <map>
#include <string>
#include <iostream>
#include <list>
#include <tchar.h>
typedef unsigned int UInt32;
#ifdef UNICODE
typedef std::wstring String;
#else
typedef std::string String;
#endif
template<typename T>
class Singleton
{
public:
virtual ~Singleton(){}
static T* Instance()
{
static T ObjectInstance;
return &ObjectInstance;
}
protected:
Singleton(){}
Singleton(const Singleton& p_Copy){}
Singleton& operator=(const Singleton<T>& p_RHS)
{
return (*this);
}
};
class ILog
{
public:
ILog(){}
virtual ~ILog(){}
virtual void Write(
const String& p_Message,
const String& p_File,
UInt32 p_Line) = 0;
virtual void Write(
const String& p_Message) = 0;
virtual ILog* Clone() = 0;
};
template<typename TBase>
class FactoryBase
{
public:
FactoryBase(){}
virtual ~FactoryBase()
{
// Destroy the prototypes
for(MapType::iterator iter = m_RegisteredTypes.begin();
m_RegisteredTypes.end() != iter;
++iter)
{
delete iter->second;
}
m_RegisteredTypes.clear();
// Destroy the created objects
for(ListType::iterator iter = m_CreatedObjects.begin();
m_CreatedObjects.end() != iter;
++iter)
{
delete *iter;
}
m_CreatedObjects.clear();
return;
}
template<typename T>
void RegisterType(const String& p_Identifier)
{
m_RegisteredTypes[p_Identifier] = new T;
}
TBase* Create(const String&)
{
m_RegisteredTypes[p_Identifier]->Clone();
m_CreatedObjects.push_back(Return);
return Return;
}
private:
typedef std::map<String,TBase*> MapType;
typedef std::list<TBase*> ListType;
MapType m_RegisteredTypes;
ListType m_CreatedObjects;
};
class LogFactory : public Singleton< LogFactory >,public FactoryBase<ILog>
{
public:
LogFactory(){}
virtual ~LogFactory(){}
};
class ConsoleLog : public ILog
{
typedef std::list<ILog*> ListType;
ListType m_ClonedLogs;
public:
ConsoleLog(){}
virtual ~ConsoleLog()
{
for( ListType::iterator iter = m_ClonedLogs.begin();
m_ClonedLogs.end() != iter;
++iter)
{
delete (*iter);
}
}
virtual void Write(
const String& p_Message,
const String& p_File,
UInt32 p_Line)
{
std::cout << "Message: " << p_Message.c_str() << "[" << p_File.c_str() << ", " << p_Line << "]" << std::endl;
}
virtual void Write(
const String& p_Message)
{
std::cout << "Message: " << p_Message.c_str() << std::endl;
}
virtual ILog* Clone()
{
ILog* Return = new ConsoleLog();
m_ClonedLogs.push_back(Return);
return Return;
}
};
int main()
{
LogFactory::Instance()->RegisterType<ConsoleLog>( _T("ConsoleLog") );
}
Does anyone have an idea of what the bug is?