Удаление объекта, который был создан в DLL - PullRequest
7 голосов
/ 20 июля 2011

Мне нужно кое-что прояснить в отношении проблем времени выполнения / кучи при удалении объекта, созданного в 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 (тогда это решение вообще не решит мою проблему)?Или эти две статические функции используют одну и ту же кучу?

Я надеюсь, что кто-то может объяснить, что здесь происходит ...

Ответы [ 3 ]

5 голосов
/ 20 июля 2011

DLL подсчитывается по ссылкам, не загружается дважды, и когда вы используете LoadLibrary, она все равно загружается только один раз, и они будут использовать одну и ту же кучу.Статическая функция является нормальным решением этой проблемы.

3 голосов
/ 20 июля 2011

Ну, это потому, что (в вашем случае) две кучи работают.У DLL есть другой менеджер кучи, а у EXE другой.Это может быть из-за:

  • Противоречия отладки / выпуска
  • Используется среда выполнения VC (одна - VC8, другая, например, VC9).Сложено и выше!
  • Различные модели, используемые для построения DLL / EXE (флаг /MT[d], ссылки как static-lib и т. Д.).
  • Вы показали delete против new, которыйявляется действительным.Но это также может быть случай, когда new на самом деле является malloc / HeapAlloc.

Короче говоря, память, выделенная X heap-manager, не будет найдена Y куча-менеджер, а значит и утверждение!

3 голосов
/ 20 июля 2011

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

РЕДАКТИРОВАТЬ: первый вопрос, вероятно, потому, что либо общий указатель никогда не выходит за рамки ИЛИ потому что среда выполнения VC не может обнаружить случайправильно (не фатально, но память не была освобождена).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...