Intereting Posts
Проверьте, использует ли версия libstdc ++ C ++ 11-совместимая std :: string Каков правильный способ получить (-1) ^ n? Правильная обработка GetLastError (и других) в многопоточном контексте Ошибка C ++ «nullptr не была объявлена ​​в этой области» в Eclipse IDE Обнаружение линии OpenCV Почему функция Boost.Bind вызывается с дополнительными параметрами? Определите переменную b того же типа, что и переменная a Несоответствие в моем понимании функции GLM lookAt Как сообщить конвейеру VTK использовать новую vtkPolyData, обновленную через TimerEvent? Почему в декларации многомерного массива используются «двойные фигурные скобки» с использованием stacked std :: array? «Приложение не удалось запустить, потому что cxcore210.dll не был найден». Почему это произойдет? следует ли использовать exit в C ++? Как инициализировать вектор из массива без выделения большего пространства для хранения? Как вы можете использовать поиск по ширине для поиска кратчайшего пути на карте? 64-разрядные проблемы с переносом по плавающей запятой

C ++ одноэлементный class с dll

Я создал статическую библиотеку с classом:

class CLog { private: CLog(); ... ... public: static CLog& GetInstance() { static CLog Instance; return Instance; } void Write(char *cpPr); }; #define Log CLog::GetInstance() 

Эта библиотека связана с dll и основной программой. DLL загружается LoadLibrary. В этом случае очевидно, что вызов Log.Write в основном exe и в dll создает два отдельных экземпляра CLog. Любые идеи, как обойти эту проблему и по-прежнему обеспечивать динамическую загрузку dll?

Проблема в том, что каждый проект, который связывает статическую библиотеку, будь то основная программа или DLL, получит отдельную копию статической переменной. Это нарушает типичный метод создания синглета.

Самый простой способ – создать другую DLL, которая содержит синглтон, а не статическую библиотеку. Поскольку только один вывод компоновщика будет содержать статическую переменную, проблема будет решена.

В моем собственном случае я создал одноэлементный менеджер, который идентифицировал каждый синглтон с помощью уникального GUID и обеспечивал, чтобы только одна копия существовала в приложении. Одиночный менеджер существовал как собственная DLL.

Метод, который я использовал, заключался в том, чтобы экспортировать функцию, называемую GetLogger из EXE, которая предоставляет указатель на singleton. Реализация GetInstance () обусловлена ​​определением препроцессора _USRDLL. Когда _USRDLL установлен (для компиляции DLL), GetInstance () вызывает GetModuleHandle (), чтобы получить дескриптор EXE и загружает функцию, называемую GetLogger. Вот код, основанный на вашем примере:

У Static 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() 

У Static 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  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; } 

Если вместо этого вы используете статический член classа (в отличие от использования статически назначенной локальной переменной), я считаю, что это создаст только один экземпляр (на данный момент я не могу проверить это). Что-то вроде:

 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. О чем-то еще нужно подумать.