Экспорт класса из DLL
От: Hayabusa Россия  
Дата: 06.08.13 15:55
Оценка:
Доброго дня всем,

Есть такая задача:
Экспортируемая функция из DLL возвращает указатель на экземпляр созданного класса.
В приложении DLL загружается динамически. Получаю указатель на экземпляр, вроде даже методы класса вызываются.
Но при попытке delete на указатель, выскакивает исключение при освобождении памяти.

Экспортируемая функция объявлена так


extern "C" CSomeClass* CALLBACK GetObject(void);


Что нужно еще сделать для нормальной работы с экземпляром класса?
Как правильно его потом освобождать?
Re: Экспорт класса из DLL
От: Logot Украина  
Дата: 06.08.13 16:20
Оценка:
Здравствуйте, Hayabusa, Вы писали:

H>Доброго дня всем,


H>Есть такая задача:

H>Экспортируемая функция из DLL возвращает указатель на экземпляр созданного класса.
H>В приложении DLL загружается динамически. Получаю указатель на экземпляр, вроде даже методы класса вызываются.
H>Но при попытке delete на указатель, выскакивает исключение при освобождении памяти.

H>Экспортируемая функция объявлена так



H>
H>extern "C" CSomeClass* CALLBACK GetObject(void);
H>


H>Что нужно еще сделать для нормальной работы с экземпляром класса?

H>Как правильно его потом освобождать?

У EXE и DLL разные менеджеры кучи, в одном манагере кучи ты выделяешь память, а в другом удаляешь. Под виндами так нельзя. Нужно, чтобы тот менеджер кучи, который выделил память, также заботился об освобождении.
Re: Экспорт класса из DLL
От: niralex  
Дата: 06.08.13 16:28
Оценка: 2 (1)
Библиотека и модуль к ней обращающийся должны использовать общий менеджер памяти. Или освобождать память в DLL, если конечно есть возможность ее переделать.
Re[2]: Экспорт класса из DLL
От: Hayabusa Россия  
Дата: 06.08.13 16:30
Оценка:
Здравствуйте, Logot, Вы писали:

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


Понял, освобождением тоже должна заниматься DLL?
Re[2]: Экспорт класса из DLL
От: Hayabusa Россия  
Дата: 06.08.13 16:31
Оценка:
Здравствуйте, niralex, Вы писали:

N>Библиотека и модуль к ней обращающийся должны использовать общий менеджер памяти. Или освобождать память в DLL, если конечно есть возможность ее переделать.


Да, возможность переделать DLL есть..

Как это будет выглядеть?
Тот указатель на экземпляр класса я передаю в другую экспортируемую ф-цию DLL и там просто делаю delete?
Re[3]: Экспорт класса из DLL
От: Hayabusa Россия  
Дата: 06.08.13 17:02
Оценка:
Здравствуйте, Hayabusa, Вы писали:

H>Тот указатель на экземпляр класса я передаю в другую экспортируемую ф-цию DLL и там просто делаю delete?


Сделал так, вроде работает..

Один момент поясните.
Нормально заработало только при таком обьявлении

extern "C" CSomeClass* CALLBACK GetObject(void);
extern "C" void /*CALLBACK*/ DelObject(CSomeClass* pObject);


Т.е. вторая функция без соглашения вызова CALLBACK, иначе при ее вызове из приложения возникал ESP fault...
Re: Экспорт класса из DLL
От: The Passenger Голландия  
Дата: 06.08.13 18:29
Оценка:
Здравствуйте, Hayabusa, Вы писали:

вообще, насколько я знаю, проблем быть не должно, если используется одинаковая рантайм библиотека,
настройки для длл и ехе для студии смотреть здесь — c/c++/code generation/runtime library — должно быть одинаково для обоих

но в связи с этим, поскольку не всем нравится смотреть кто как слинкован, хорошая практика — создавать
и удалять объекты ( выделять и освобождать память) внутри модуля ... но еще можно использовать рантаймнезависимые функции типа — CoTaskMemAlloc/CoTaskMemFree
и другие ... но это если нет другого выбора.
Весь мир — Кремль, а люди в нем — агенты
Re[2]: Экспорт класса из DLL
От: Hayabusa Россия  
Дата: 06.08.13 18:38
Оценка:
Здравствуйте, The Passenger, Вы писали:

TP>Здравствуйте, Hayabusa, Вы писали:


TP>вообще, насколько я знаю, проблем быть не должно, если используется одинаковая рантайм библиотека,

TP>настройки для длл и ехе для студии смотреть здесь — c/c++/code generation/runtime library — должно быть одинаково для обоих

Рантайм естессна один, прилинкован в обоих проектах статически..
Сделал освобождение памяти в DLL.
По этому посту можете что нибудь сказать? http://www.rsdn.ru/forum/cpp/5253111.1
Автор: Hayabusa
Дата: 06.08.13
а то я в непонятках..
Re[3]: Экспорт класса из DLL
От: GreyMan  
Дата: 06.08.13 18:45
Оценка:
Здравствуйте, Hayabusa, Вы писали:
H>Как это будет выглядеть?
H>Тот указатель на экземпляр класса я передаю в другую экспортируемую ф-цию DLL и там просто делаю delete?
Да метод класса. (Возможно, виртуальный) Зачем внешная функция?
Вон на IUnknown гляньте.
Re[4]: Экспорт класса из DLL
От: Hayabusa Россия  
Дата: 06.08.13 19:05
Оценка:
Здравствуйте, GreyMan, Вы писали:

GM>Да метод класса. (Возможно, виртуальный) Зачем внешная функция?

GM>Вон на IUnknown гляньте.

Как это, не совсем пойму?
А деструктор когда вызывать?
Re[5]: Экспорт класса из DLL
От: GreyMan  
Дата: 06.08.13 19:34
Оценка: 2 (1)
Здравствуйте, Hayabusa, Вы писали:

H>Как это, не совсем пойму?

H>А деструктор когда вызывать?

Так изнутри метода и вызовется.

struct Foo{
   void Del();
}
void Del::Foo(){
  delete this;
}
Re[6]: Экспорт класса из DLL
От: Hayabusa Россия  
Дата: 06.08.13 19:46
Оценка:
Здравствуйте, GreyMan, Вы писали:

GM>Так изнутри метода и вызовется.


GM>
GM>struct Foo{
GM>   void Del();
GM>}
GM>void Del::Foo(){
GM>  delete this;
GM>}
GM>


Работает, отлично
Re: Экспорт класса из DLL
От: Erop Россия  
Дата: 06.08.13 22:41
Оценка:
Здравствуйте, 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...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Экспорт класса из DLL
От: Pavel Dvorkin Россия  
Дата: 07.08.13 03:11
Оценка: 4 (1)
Здравствуйте, Hayabusa, Вы писали:


H>
H>extern "C" CSomeClass* CALLBACK GetObject(void);
H>extern "C" void /*CALLBACK*/ DelObject(CSomeClass* pObject);
H>


H>Т.е. вторая функция без соглашения вызова CALLBACK, иначе при ее вызове из приложения возникал ESP fault...


CALLBACK — это _stdcall (см. windef.h). А у тебя в программе, скорее всего, ничего насчет соглашений о связях нет, поэтому по умолчанию _cdecl. В итоге функция в DLL при CALLBACK имеет соглашение _stdcall, а вызывается как _cdecl.
_stdcall сама чистит стек перед выходом, а для _cdecl стек чистит тот, кто ее вызывает. В итоге стек очищается дважды

GetObject тоже должна, по-хорошему, быть _cdecl, то есть без CALLBACK, но ей что _cdecl, что _stdcall — все равно, так как параметров у нее нет и стек чистить не приходится. Добавь ей какой-нибудь параметр — вылетит и она
With best regards
Pavel Dvorkin
Re[6]: Экспорт класса из DLL
От: Caracrist https://1pwd.org/
Дата: 07.08.13 05:26
Оценка:
Здравствуйте, GreyMan, Вы писали:

GM>Здравствуйте, Hayabusa, Вы писали:


H>>Как это, не совсем пойму?

H>>А деструктор когда вызывать?

struct Foo{
   virtual ~Foo();
};

Foo * foo = CreateNewInSomeDll();
delete foo;

~~~~~
~lol~~
~~~ Single Password Solution
Re[3]: Экспорт класса из DLL
От: eqw  
Дата: 07.08.13 05:30
Оценка: +1
Здравствуйте, Hayabusa, Вы писали:


H>Рантайм естессна один, прилинкован в обоих проектах статически..

Взаимоисключающие параграфы детектед. Раз в каждом проекте по статическому рантайму, то рантаймов уже минимум 2
Re[3]: Экспорт класса из DLL
От: The Passenger Голландия  
Дата: 07.08.13 06:43
Оценка:
Здравствуйте, Hayabusa, Вы писали:

H>Рантайм естессна один, прилинкован в обоих проектах статически..

H>Сделал освобождение памяти в DLL.
H>По этому посту можете что нибудь сказать? http://www.rsdn.ru/forum/cpp/5253111.1
Автор: Hayabusa
Дата: 06.08.13
а то я в непонятках..


здесь можно покурить — соглашение вызова

вроде как по умолчанию ( не на 100% уверен) должен быть cdecl а вы обьявляете stdcall
Весь мир — Кремль, а люди в нем — агенты
Re[2]: Экспорт класса из DLL
От: Caracrist https://1pwd.org/
Дата: 07.08.13 07:24
Оценка:
Здравствуйте, Erop, Вы писали:

E>Если хочешь сделать работу с этим классом более прозрачной для пользователя, то можешь добавить в него одновременно виртуальный деструктор и операторы new и delete, с тривиальным редеректом на глобальные в той DLL.


и обязательно не забыть заморочиться со всеми публичными методами и полями, все должно быть в экспортируемом формате, особенно возвращаемые параметры. То есть либо не пользоваться std контейнерами, либо с кастомным алокатором.
~~~~~
~lol~~
~~~ Single Password Solution
Re[3]: Экспорт класса из DLL
От: Erop Россия  
Дата: 07.08.13 08:19
Оценка: :)
Здравствуйте, Caracrist, Вы писали:

C>и обязательно не забыть заморочиться со всеми публичными методами и полями, все должно быть в экспортируемом формате, особенно возвращаемые параметры. То есть либо не пользоваться std контейнерами, либо с кастомным алокатором.


+100500
Это тема тонкая...
но лучше да, STL в такие штуки не тащить, во всяком случае в интерфейс.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.