Есть такая задача:
Экспортируемая функция из DLL возвращает указатель на экземпляр созданного класса.
В приложении DLL загружается динамически. Получаю указатель на экземпляр, вроде даже методы класса вызываются.
Но при попытке delete на указатель, выскакивает исключение при освобождении памяти.
Экспортируемая функция объявлена так
extern"C" CSomeClass* CALLBACK GetObject(void);
Что нужно еще сделать для нормальной работы с экземпляром класса?
Как правильно его потом освобождать?
Здравствуйте, Hayabusa, Вы писали:
H>Доброго дня всем,
H>Есть такая задача: H>Экспортируемая функция из DLL возвращает указатель на экземпляр созданного класса. H>В приложении DLL загружается динамически. Получаю указатель на экземпляр, вроде даже методы класса вызываются. H>Но при попытке delete на указатель, выскакивает исключение при освобождении памяти.
H>Экспортируемая функция объявлена так
H>Что нужно еще сделать для нормальной работы с экземпляром класса? H>Как правильно его потом освобождать?
У EXE и DLL разные менеджеры кучи, в одном манагере кучи ты выделяешь память, а в другом удаляешь. Под виндами так нельзя. Нужно, чтобы тот менеджер кучи, который выделил память, также заботился об освобождении.
Библиотека и модуль к ней обращающийся должны использовать общий менеджер памяти. Или освобождать память в DLL, если конечно есть возможность ее переделать.
Здравствуйте, Logot, Вы писали:
L>У EXE и DLL разные менеджеры кучи, в одном манагере кучи ты выделяешь память, а в другом удаляешь. Под виндами так нельзя. Нужно, чтобы тот менеджер кучи, который выделил память, также заботился об освобождении.
Здравствуйте, niralex, Вы писали:
N>Библиотека и модуль к ней обращающийся должны использовать общий менеджер памяти. Или освобождать память в DLL, если конечно есть возможность ее переделать.
Да, возможность переделать DLL есть..
Как это будет выглядеть?
Тот указатель на экземпляр класса я передаю в другую экспортируемую ф-цию DLL и там просто делаю delete?
вообще, насколько я знаю, проблем быть не должно, если используется одинаковая рантайм библиотека,
настройки для длл и ехе для студии смотреть здесь — c/c++/code generation/runtime library — должно быть одинаково для обоих
но в связи с этим, поскольку не всем нравится смотреть кто как слинкован, хорошая практика — создавать
и удалять объекты ( выделять и освобождать память) внутри модуля ... но еще можно использовать рантаймнезависимые функции типа — CoTaskMemAlloc/CoTaskMemFree
и другие ... но это если нет другого выбора.
Здравствуйте, The Passenger, Вы писали:
TP>Здравствуйте, Hayabusa, Вы писали:
TP>вообще, насколько я знаю, проблем быть не должно, если используется одинаковая рантайм библиотека, TP>настройки для длл и ехе для студии смотреть здесь — c/c++/code generation/runtime library — должно быть одинаково для обоих
Рантайм естессна один, прилинкован в обоих проектах статически..
Сделал освобождение памяти в DLL.
По этому посту можете что нибудь сказать? http://www.rsdn.ru/forum/cpp/5253111.1
Здравствуйте, Hayabusa, Вы писали: H>Как это будет выглядеть? H>Тот указатель на экземпляр класса я передаю в другую экспортируемую ф-цию DLL и там просто делаю delete?
Да метод класса. (Возможно, виртуальный) Зачем внешная функция?
Вон на IUnknown гляньте.
Здравствуйте, Hayabusa, Вы писали:
H>Как правильно его потом освобождать?
Если хочешь сделать работу с этим классом более прозрачной для пользователя, то можешь добавить в него одновременно виртуальный деструктор и операторы new и delete, с тривиальным редеректом на глобальные в той DLL.
Виртуальный деструктор, кроме всего прочего гарантирует ещё и вызов operator delete из нужного потомка...
Всё это можно завернуть в что-то вроде
class SafeDeletable {
protected:
void* operator new( size_t size ) { return ::operator new( size ); }
void operator delete( void* p ) { ::operator delete( p ); }
void* operator new[]( size_t size ) { return ::operator new[]( size ); }
void operator delete[]( void* p ) { ::operator delete[]( p ); }
// тут можно ещё каких-то new наредеректить, например шаблонных для двух-трёх параметровvirtual ~SafeDeletable() {}
};
ну и выводить такие кросс-DLL-ные классы из SafeDeletable...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
H>Т.е. вторая функция без соглашения вызова CALLBACK, иначе при ее вызове из приложения возникал ESP fault...
CALLBACK — это _stdcall (см. windef.h). А у тебя в программе, скорее всего, ничего насчет соглашений о связях нет, поэтому по умолчанию _cdecl. В итоге функция в DLL при CALLBACK имеет соглашение _stdcall, а вызывается как _cdecl.
_stdcall сама чистит стек перед выходом, а для _cdecl стек чистит тот, кто ее вызывает. В итоге стек очищается дважды
GetObject тоже должна, по-хорошему, быть _cdecl, то есть без CALLBACK, но ей что _cdecl, что _stdcall — все равно, так как параметров у нее нет и стек чистить не приходится. Добавь ей какой-нибудь параметр — вылетит и она
H>Рантайм естессна один, прилинкован в обоих проектах статически..
Взаимоисключающие параграфы детектед. Раз в каждом проекте по статическому рантайму, то рантаймов уже минимум 2
Здравствуйте, Hayabusa, Вы писали:
H>Рантайм естессна один, прилинкован в обоих проектах статически.. H>Сделал освобождение памяти в DLL. H>По этому посту можете что нибудь сказать? http://www.rsdn.ru/forum/cpp/5253111.1
Здравствуйте, Erop, Вы писали:
E>Если хочешь сделать работу с этим классом более прозрачной для пользователя, то можешь добавить в него одновременно виртуальный деструктор и операторы new и delete, с тривиальным редеректом на глобальные в той DLL.
и обязательно не забыть заморочиться со всеми публичными методами и полями, все должно быть в экспортируемом формате, особенно возвращаемые параметры. То есть либо не пользоваться std контейнерами, либо с кастомным алокатором.
Здравствуйте, Caracrist, Вы писали:
C>и обязательно не забыть заморочиться со всеми публичными методами и полями, все должно быть в экспортируемом формате, особенно возвращаемые параметры. То есть либо не пользоваться std контейнерами, либо с кастомным алокатором.
+100500
Это тема тонкая...
но лучше да, STL в такие штуки не тащить, во всяком случае в интерфейс.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском