我用类创建了一个静态库:
class CLog
{
private:
CLog();
...
...
public:
static CLog& GetInstance()
{
static CLog Instance;
return Instance;
}
void Write(char *cpPr);
};
#define Log CLog::GetInstance()
此库链接到dll和主程序。该DLL由LoadLibrary加载。在这种情况下很明显,在主exe和dll中调用Log.Write会创建两个独立的CLog实例。任何想法如何解决这个问题仍然提供动态加载DLL?
答案 0 :(得分:10)
问题是每个链接静态库的项目,无论是主程序还是DLL,都会获得静态变量的单独副本。这打破了创建单例的典型方法。
最简单的方法是创建另一个包含单例的DLL,而不是静态库。由于只有一个链接器输出将包含静态变量,因此问题得以解决。
在我自己的案例中,我创建了一个单例管理器,它通过唯一的GUID识别每个单例,并确保应用程序范围内只存在一个副本。单例管理器作为自己的DLL存在。
答案 1 :(得分:1)
我使用的方法是从EXE导出一个名为GetLogger的函数,该函数提供指向单例的指针。 GetInstance()实现是以_USRDLL预处理器定义为条件的。设置_USRDLL时(对于DLL编译),GetInstance()调用GetModuleHandle()来获取EXE的句柄并加载名为GetLogger的函数。以下是基于您的示例的代码:
静态lib具有Log.h:
class Log
{
private:
Log();
public:
~Log();
static Log& GetInstance()
{
#ifdef _USRDLL
typedef Log* (*GetLoggerFn)();
HMODULE mod = GetModuleHandle( NULL );
GetLoggerFn getLogger = (GetLoggerFn)::GetProcAddress( mod, "GetLogger" );
Log* Instance = getLogger();
return *Instance;
#else
static Log Instance;
return Instance;
#endif
}
void Write(const std::string& str );
};
#define LOG Log::GetInstance()
静态lib具有Log.cpp:
#include "Log.h"
void Log::Write(const std::string& str )
{
std::cout << this << " " << str << std::endl;
}
Log::Log()
{
}
Log::~Log()
{
std::cout << "Log destroyed" << std::endl;
}
DLL在DllMain中只有一个日志语句:
#include "../static/Log.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
LOG.Write("Hello from dll");
return TRUE;
}
EXE看起来像这样:
#include "stdafx.h"
#include "../static/Log.h"
#include <Windows.h>
extern "C"
{
__declspec( dllexport ) Log* GetLogger()
{
return &LOG;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
LOG.Write("Hello from exe");
HMODULE mod = ::LoadLibraryA( "../Debug/tdll.dll");
::FreeLibrary( mod );
LOG.Write("unloaded library");
return 0;
}
答案 2 :(得分:0)
如果您改为使用静态类成员(而不是使用静态分配的局部变量),我相信这只会创建一个实例(我目前无法验证这一点)。类似的东西:
class CLog
{
private:
CLog();
static CLog instance;
public:
static CLog & GetInstance( )
{
return instance;
}
void Write(char *cpPr);
};
CLog CLog::instance; // I believe this is also necessary
好吧,马克指出这也行不通。 DLL和EXE仍然获得不同的CLog实例。还必须考虑其他因素。