C ++带有dll的单例类

时间:2011-08-04 02:30:00

标签: c++ dll static

我用类创建了一个静态库:

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?

3 个答案:

答案 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实例。还必须考虑其他因素。