Lex
|
|
« : 23-12-2003 11:50 » |
|
Проблема в следующем. Есть dll созданная с использованием статической библиотеки MFC в ней есть функция PMYSTRUCT FAR PASCAL EXPORT GetMyStruct() { AFX_MANAGE_STATE(AfxGetStaticModuleState());
PMYSTRUCT pm; pm = new MYSTRUCT[20];
// заполняем pm
return pm; }
В основном модуле делаем следующее: if (GetMyStruct == NULL) return; // dll подгружается динамически
PMYSTRUCT pm = GetMyStruct(); // обрабатываем pm delete[] pm;
при выполнении delete[] pm выскакивает ASSERT, что указатель неправильный. Где зарылась бага?
|
|
« Последнее редактирование: 23-11-2007 16:08 от Алексей1153++ »
|
Записан
|
Megabyte be with you!
|
|
|
GlukSoft
Главный специалист
Offline
Пол:
|
|
« Ответ #1 : 23-12-2003 12:24 » |
|
Lex, а указатель изначально возвращается правильный? Есть подозрения, что проблема в том, что основной модуль не знает сколько было выделено памяти в dll.
|
|
|
Записан
|
Fatal error C1: Brain expected
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #2 : 23-12-2003 12:32 » |
|
PMYSTRUCT pm; pm = new MYSTRUCT[20];
а разве pm не должен быть указателем? PMYSTRUCT *pm; pm = new MYSTRUCT[20]; или это тип какой-то специальный...
|
|
|
Записан
|
|
|
|
GlukSoft
Главный специалист
Offline
Пол:
|
|
« Ответ #3 : 23-12-2003 12:45 » |
|
Алексей1153, память выделяется для MYSTRUCT, а присвоение идет типу PMYSTRUCT, судя по префиксу P тип определен как указатель на MYSTRUCT типа typedef MYSTRUCT* PMYSTRUCT.
|
|
|
Записан
|
Fatal error C1: Brain expected
|
|
|
Lex
|
|
« Ответ #4 : 23-12-2003 13:03 » |
|
судя по префиксу P тип определен как указатель на MYSTRUCT типа typedef MYSTRUCT* PMYSTRUCT.
Угу так оно и есть, сорри что забыл написасть. Указатель возвращается правильный. Эта моя структура нормально обрабатывается. И если закоментировать delete[] pm , то программа работает, но оставляет после себя неосвобожденную память, что не есть гуд. Вопрос собственно такой, как правильно удалить такой указатель из основной програмы.
|
|
|
Записан
|
Megabyte be with you!
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #5 : 23-12-2003 13:15 » |
|
А MFC operator new[](size_t size) как-нибудь хитро не переопределяет. Если она его переопределила, то она наверно как-то по своему оббивает начало и конец выделенной памяти. Если мое предположение верно- то надо использовать operator delete[] из MFC.
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #6 : 23-12-2003 13:19 » |
|
Удаление через delete[] вполне корректно. Пробовал проверить на gcc с промежуточным выводом в asm-е: new получает в качестве параметра _размер_требуемомой_памяти_ (20*sizeof(MYSTRUCT)), а delete[] просто удаляет его (передаваемый параметер один - указатель). Сведения о размере выделенной памяти сохраняет runtime библиотека и динамическая библиотека здесь не помеха.
Попробуй сделать тот же самое в пределах одного модуля.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Lex
|
|
« Ответ #7 : 23-12-2003 13:27 » |
|
Попробуй сделать тот же самое в пределах одного модуля.
В пределах одного модуля все работает и не ругается. Как мне кажется тут есть какаята макрософтовская фича, о которой надо знать, когда модуль проектируешь.
|
|
|
Записан
|
Megabyte be with you!
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #8 : 23-12-2003 13:28 » |
|
Как мне кажется тут есть какаята макрософтовская фича, о которой надо знать, когда модуль проектируешь.
А dll и прога ее вызывающая собраны с использованием MFC?
|
|
|
Записан
|
|
|
|
GlukSoft
Главный специалист
Offline
Пол:
|
|
« Ответ #9 : 23-12-2003 13:32 » |
|
Lex, а если попробовать так: for (i = 0; i < 20; i++) delete pm++;
|
|
|
Записан
|
Fatal error C1: Brain expected
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #10 : 23-12-2003 13:40 » |
|
for (i = 0; i < 20; i++) delete pm++;
Ну это уж совсем. Офигительно неправильная операция(извини за резкость- но это ужасная ошибка, делать так как ты предложил). Никогда так делать нельзя- перед началом выделенной области и после ее конца находится служебная инфа, в таком случае в роли этой инфы выступят элементы массива. Выделил operator new[](...) - удаляй operator delete[](void*).
|
|
|
Записан
|
|
|
|
Lex
|
|
« Ответ #11 : 23-12-2003 13:45 » |
|
Николай, это будет точно не правильно, т.к. память у меня выделяется одним куском. Вместо new я могу написать pm = (PMYSTRUCT)malloc(20 * sizeof(MYSTRUCT));
но при вызове free(pm) все равно возникнет ошибка
|
|
« Последнее редактирование: 23-11-2007 16:09 от Алексей1153++ »
|
Записан
|
Megabyte be with you!
|
|
|
Lex
|
|
« Ответ #12 : 23-12-2003 14:02 » |
|
Нда, проблема решилась заменой new/delete на HeapAlloc(GetProcessHeap(), .....)/HeapFree(GetProcessHeap(), .....)
Странно. Исходя из MSDN malloc и new, по идее должны использовать эти же функции.
|
|
|
Записан
|
Megabyte be with you!
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #13 : 23-12-2003 14:15 » |
|
Нда, проблема решилась заменой new/delete на HeapAlloc(GetProcessHeap(), .....)/HeapFree(GetProcessHeap(), .....)
Странно. Исходя из MSDN malloc и new, по идее должны использовать эти же функции.
А ты мои посты выше читал? Вероятно в дебажной версии MFC заменен operator new[]() и operator delete[](). И если dll собрана с MFC в дебажном варианте, а exe- нет, то в этом причина. Проблема- в несоответствии new и delete(один из MFC, другой из CRT), они помимо HeapAlloc(GetProcessHeap(), .....)/HeapFree(GetProcessHeap(), .....) вероятно еще свои заголовки использовали.
|
|
|
Записан
|
|
|
|
Lex
|
|
« Ответ #14 : 23-12-2003 14:39 » |
|
SlavaI, все в дебажном варианте. Про переопределение это я знаю, но в все равно должно вызываться HeapAlloc() (хотя я могу быть и не прав). Всякие GlobalAlloc LocalAlloc в Win32 согласно MSDN в итоге вызывают HeapAlloc(). и это сделано для совместимости с 16-битными приложениями. Единственный возможный вариант это то, что MFC использует разные кучи для каждого модуля. Пойду покопаюсь в исходниках MFC.
|
|
|
Записан
|
Megabyte be with you!
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #15 : 23-12-2003 14:46 » |
|
Пойду покопаюсь в исходниках MFC
И охота тебе в этом копаться . Как ты дошел до такой жизни- использовать MFC? Проект что ли старый очень?
|
|
|
Записан
|
|
|
|
Lex
|
|
« Ответ #16 : 23-12-2003 15:07 » |
|
Как ты дошел до такой жизни- использовать MFC? Проект что ли старый очень?
Угу ему ужо лет 5 будет, а то и больше. В общем в MFC они просто _malloc_dbg() /_free_dbg() вызывают А те в свою очередь уже занимаются вызовом HeapAlloc()/HeapFree(). Слава, кстати, я менял new на malloc() та же фигня. Ты случаем не в курсе, как эти кучи распределяются по загруженным модулям и основной программе?
|
|
|
Записан
|
Megabyte be with you!
|
|
|
Mouse
Молодой специалист
Offline
|
|
« Ответ #17 : 23-12-2003 16:07 » |
|
У меня давно было что-то подобное. У меня дело было вот в чем: я пытался удалять указатель дважды, т.е. (на данном примере) первый раз в GetMyStruct(), а второй раз уже в вызывающем модуле непосредственно delete'ом. Проверь эту тему. Конкретно в чем дело, я тогда не копал - исправил и забыл... Просто смотри, Lex: область видимости переменной pm - функция GetMyStruct(). А ведь по выходе указатель удаляется автоматически! По крайней мере так должно быть. Просто по идее GetMyStruct() возвращает указатель, который по выходе из функции уничтожается, т.е. система считает его = NULL. Слушай, а в основном модуле обработка pm шла корректно?
|
|
|
Записан
|
|
|
|
Lex
|
|
« Ответ #18 : 23-12-2003 16:54 » |
|
Archangel Я же описал проблема имено в том, что new в dll и delete в програме пытаются использовать разные кучи, как я понял. Меня сейчас интересует приведение этих куч к единому знаменателю, чтобы можно было пользовать new/delete. Самому подменять стандартный new/delete не сильно хочется
|
|
|
Записан
|
Megabyte be with you!
|
|
|
NetRaider
Гость
|
|
« Ответ #19 : 24-12-2003 05:41 » |
|
Я же описал проблема имено в том, что new в dll и delete в програме пытаются использовать разные кучи, как я понял. Меня сейчас интересует приведение этих куч к единому знаменателю, чтобы можно было пользовать new/delete. Самому подменять стандартный new/delete не сильно хочется
Попробуй выставить у обоих проектов одинаковые run-time library. Или нужно экспортировать из DLL функции работы с памятью DllAlloc(), DllFree(). И использовать только их для выделения памяти при работе с этой DLL. Кстати кучи не разные, - она одна. Проблема в том что CRT сохраняет информацию о выделенной памити в своих внутренних структурах, - а вот их может быть несколько - по одной для каждой копии библиотеки, статически прилинкованной к EXE или DLL.
|
|
|
Записан
|
|
|
|
little
|
|
« Ответ #20 : 24-12-2003 07:58 » |
|
У меня подобная проблема была, и я спрашивал об этом на форуме, но тогда пришли к мнению, что я что-то где упустил. Динамически созданный класс возвращал указатель на выделенный массив, затем класс уничтожался. И начинались такие танцы с бубнами... память то выделялась, то нет. Заказываешь один объем - выделяется, заказываешь меньший(!) - вылетает.
|
|
|
Записан
|
|
|
|
Lex
|
|
« Ответ #21 : 24-12-2003 10:18 » |
|
NetRaider, куч несколько. Точнее там все намного хитрее. Достаточно большая пляска идет с выделением виртуальных страниц. И вся эта инфа, кстати, цепляется к выделеному блоку.
|
|
|
Записан
|
Megabyte be with you!
|
|
|
NetRaider
Гость
|
|
« Ответ #22 : 25-12-2003 06:56 » |
|
Достаточно большая пляска идет с выделением виртуальных страниц. И вся эта инфа, кстати, цепляется к выделеному блоку.
Цепляется... И сохраняется в списке, состоящем из экземпляров _CrtMemBlockHeader. А экземпляров этих списков может быть несколько. Отсюда и проблемы - выделил кусок память - информация о нем сохранилась в списке. Удалять надо и этого же списка, а не из другого.
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #23 : 25-12-2003 09:54 » |
|
На основе всего сказанного, получается что для отладки можно включить в динамическую библиотеку ф-ии удаления и через них освобождать занятую библиотекой память. Пример: void do_delete(void *p) { delete p; } void do_delete_array(void *p) { delete[] p; }
|
|
« Последнее редактирование: 23-11-2007 16:10 от Алексей1153++ »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Anonymous
Гость
|
|
« Ответ #24 : 25-12-2003 14:36 » |
|
Lex, если проблема ещё не решена, то:
попробуй определить глобальную переменную и экспортируй её из dll
#define MYDLL __declspec(dllexport)
extern MYDLL PMYSTRUCT g_pMyStruct;
потом в функции:
g_pMyStruct = new MYSTRUCT[20];
а в основном модуле пользуйся g_pMyStruct.
Джон
|
|
|
Записан
|
|
|
|
Lex
|
|
« Ответ #25 : 25-12-2003 14:59 » |
|
Джон задачу решил. А в товоем примере все равно вылезет ошибка при вызове delete, т.к. память выделяется в одном блоке(принадлежащем dll) а удаятся из другого блока(принадлежащего программе).
|
|
|
Записан
|
Megabyte be with you!
|
|
|
Boris Tkach
Гость
|
|
« Ответ #26 : 22-01-2004 08:51 » |
|
Насколько я понимаю так делать нельзя. Чтобы это работало можно переопределить new, delete и заставить их все работать через одно место во всем проекте. Или добавлять в dll метод для освобождения полученного указателя. Кстати, такая же проблема будет если передать объект (например std::vector) в dll и там его изменить (добавить элементы). Правда если при сборке указываются одинаковые run-time библиотеки, совпадают ключи отладки и т.д. - то будет работать (иногда).
|
|
|
Записан
|
|
|
|
Lex
|
|
« Ответ #27 : 22-01-2004 11:32 » |
|
Boris Tkach, понятно, что нельзя возникает вопрос почему?
|
|
|
Записан
|
Megabyte be with you!
|
|
|
Джон
просто
Администратор
Offline
Пол:
|
|
« Ответ #28 : 22-01-2004 13:14 » |
|
Lex, Слушай, я так (или почти так) делал - работало и работает уже года два поэтому и тебе советовал. А вот тепрь сомневатся начал - чую, что-то не то. Правда соблюдены условия: при сборке указываются одинаковые run-time библиотеки, совпадают ключи отладки и т.д.
В общем если время и желание есть - я могу код откопать посмотреть? Почему оно работает. Схема такая была: был экзешник, была длл статическая, и в неё загружаемые динамически другие длл. Короче, общий класс был Порт, а в зависимости от того какие у тебя порты проинсталлены - загружались СОМ, LPT USB и тд дллки. Соответствующие объекты создавались с new в длл. Или я не правильно себе картину представляю и речь идёт о другом. Да, это не были библиотеки расширения MFC, а простые Win32 API. Хотя такое я тоже где-то делал из длл экспортировал диалоги. Но может там по-другому было (не уверен).
|
|
|
Записан
|
Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома. "Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash "Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman "All science is either physics or stamp collecting." Ernest Rutherford "Wer will, findet Wege, wer nicht will, findet Gründe."
|
|
|
Lex
|
|
« Ответ #29 : 22-01-2004 18:36 » |
|
Джон, понял ты правильно. И задача у меня похожая. У меня есть основное окно и куча dll, которые описывают разные типы приемников, загружаемые динамически.
Проблему я решил, но осталось недопонимание причин проблемы. Мое видение было таково, что все dll грузятся в адресное пространство процесса и память всегда выделяется в адресном пространстве процесса. Из этого я делал вывод, что все равно где вызывать new и delete(также как malloc и free). Оказалось, что это не так, по крайней мере не всегда. Вот и хочется понять почему.
|
|
|
Записан
|
Megabyte be with you!
|
|
|
|