Мне нужно кое-что прояснить в отношении проблем времени выполнения / кучи при удалении объекта, созданного в DLL.Прежде чем я подойду к своим вопросам, нужно некоторое введение ...
В моем проекте DLL (которая указана в ее имени) возвращает новый объект Grabber.В более ранней версии моего кода DLL экспортировала такую функцию:
extern "C"
__declspec(dllexport) Grabber* CreateGrabber(string settings)
{
return new SomeSpecificGrabber(settings);
}
В EXE-файле я использовал статическую функцию, подобную этой, для создания нового объекта Grabber:
static Grabber* createGrabberObject(const std::string& grabberType, const std::string& grabberSettings)
{
FARPROC hProc = 0;
// load dll with the name of grabberType
HMODULE hDLL = LoadLibrary(grabberType.c_str());
// get address for CreateGrabber function
hProc = GetProcAddress(hDLL, "CreateGrabber");
// instantiate a function pointer of our type and typecast the address
// of the CreateGrabber function to this type
CreateGrabberFunctionType CreateGrabberFunction = (CreateGrabberFunctionType)hProc;
// call CreateGrabber in DLL to get a Grabber object
return CreateGrabberFunction(grabberSettings);
}
В EXE время жизни объекта Grabber управляется умным указателем:
shared_ptr<Grabber> myGrabberObj = shared_ptr<Grabber>(createGrabberObject("SomeGrabber.DLL", "Settings"));
Все это работало нормально, пока я компилировал EXE и DLL с настройкой /MDd
(VC ++ 2010), что означает, что EXE и DLL использовали одну и ту же кучу.
Теперь я хочу скомпилировать свое решение с настройкой /MTd
.После этого я получил утверждение времени выполнения типа _CrtIsValidHeapPointer
для объекта строки настроек, который я передал в DLL.Это имеет смысл, потому что DLL пытается удалить строковый объект, который был создан в EXE.И они больше не используют одну и ту же кучу.
Я решил эту проблему, немного изменив экспортированную функцию DLL (const char*
вместо string
):
extern "C"
__declspec(dllexport) Grabber* CreateGrabber(const char* settings)
{
return new SomeSpecificGrabber(settings);
}
И в createGrabberObject
я передаю grabberSettings.c_str()
вместо grabberSettings
функции DLL.
Теперь все снова работает нормально.Но теперь приходит мой первый вопрос : почему я не получаю утверждение _CrtIsValidHeapPointer
при удалении myGrabberObj
?Объект был создан из библиотеки DLL, но удален из библиотеки EXE (с помощью интеллектуального указателя).Почему у меня не возникает та же проблема, что и с указанным выше строковым объектом?
Полагаю, чистым решением было бы то, что DLL также экспортирует такую функцию:
extern "C"
__declspec(dllexport) void DeleteGrabber(Grabber* grabber)
{
delete grabber;
}
ТогдаУ меня также была бы статическая функция в моем EXE, которая вызывает DeleteGrabber в DLL:
static void deleteGrabberObject(const std::string& grabberType, Grabber* grabber)
{
FARPROC hProc = 0;
// load dll with the name of grabberType
HMODULE hDLL = LoadLibrary(grabberType.c_str());
// get address for DeleteGrabber function
hProc = GetProcAddress(hDLL, "DeleteGrabber");
// instantiate a function pointer of our type and typecast the address
// of the DeleteGrabber function to this type
DeleteGrabberFunctionType DeleteGrabberFunction = (DeleteGrabberFunctionType)hProc;
// call DeleteGrabber in DLL
DeleteGrabberFunction(grabber);
}
Эта статическая функция может затем автоматически вызываться умным указателем:
shared_ptr<Grabber> myGrabberObj = shared_ptr<Grabber>(createGrabberObject("SomeGrabber.DLL", "Settings"),
boost::bind(deleteGrabberObject, "SomeGrabber.DLL", _1));
Это такжеработает.Но вот мой второй вопрос : статические функции createGrabberObject
и deleteGrabberObject
обе загружают DLL.Означает ли это, что создаются две разные кучи, потому что загружены два экземпляра DLL (тогда это решение вообще не решит мою проблему)?Или эти две статические функции используют одну и ту же кучу?
Я надеюсь, что кто-то может объяснить, что здесь происходит ...