Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2  Все   Вниз
  Печать  
Автор Тема: Удаление массива  (Прочитано 41043 раз)
0 Пользователей и 13 Гостей смотрят эту тему.
Lex
Специалист

ru
Offline Offline

WWW
« : 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
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 23-12-2003 12:24 » 

Lex, а указатель изначально возвращается правильный?
Есть подозрения, что проблема в том, что основной модуль не знает сколько было выделено памяти в dll.
Записан

Fatal error C1: Brain expected
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #2 : 23-12-2003 12:32 » 

Цитата

PMYSTRUCT pm;
    pm = new MYSTRUCT[20];



а разве pm не должен быть указателем?

PMYSTRUCT *pm;
    pm = new MYSTRUCT[20];

или это тип какой-то специальный...
Записан

GlukSoft
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 23-12-2003 12:45 » 

Алексей1153, память выделяется для MYSTRUCT, а присвоение идет типу PMYSTRUCT, судя по префиксу P тип определен как указатель на MYSTRUCT типа typedef MYSTRUCT* PMYSTRUCT.
Записан

Fatal error C1: Brain expected
Lex
Специалист

ru
Offline Offline

WWW
« Ответ #4 : 23-12-2003 13:03 » 

Цитата

судя по префиксу P тип определен как указатель на MYSTRUCT типа typedef MYSTRUCT* PMYSTRUCT.

Угу так оно и есть, сорри что забыл написасть.

Указатель возвращается правильный. Эта моя структура нормально обрабатывается. И если закоментировать delete[] pm , то программа работает, но оставляет после себя неосвобожденную память, что не есть гуд. Вопрос собственно такой, как правильно удалить такой указатель из основной програмы.
Записан

Megabyte be with you!
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #5 : 23-12-2003 13:15 » 

А MFC operator new[](size_t size) как-нибудь хитро не переопределяет. Если она его переопределила, то она наверно как-то по своему оббивает начало и конец выделенной памяти. Если мое предположение верно- то надо использовать operator delete[] из MFC.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 23-12-2003 13:19 » 

Удаление через delete[] вполне корректно. Пробовал проверить на gcc с промежуточным выводом в asm-е: new получает в качестве параметра _размер_требуемомой_памяти_ (20*sizeof(MYSTRUCT)), а delete[] просто удаляет его (передаваемый параметер один - указатель). Сведения о размере выделенной памяти сохраняет runtime библиотека и динамическая библиотека здесь не помеха.

Попробуй сделать тот же самое в пределах одного модуля.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Lex
Специалист

ru
Offline Offline

WWW
« Ответ #7 : 23-12-2003 13:27 » 

Цитата

Попробуй сделать тот же самое в пределах одного модуля.


В пределах одного модуля все работает и не ругается.
Как мне кажется тут есть какаята макрософтовская фича, о которой надо знать, когда модуль проектируешь.
Записан

Megabyte be with you!
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #8 : 23-12-2003 13:28 » 

Цитата

Как мне кажется тут есть какаята макрософтовская фича, о которой надо знать, когда модуль проектируешь.


А dll и прога ее вызывающая собраны с использованием MFC?
Записан
GlukSoft
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 23-12-2003 13:32 » 

Lex, а если попробовать так:
for (i = 0; i < 20; i++)
delete pm++;
Записан

Fatal error C1: Brain expected
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #10 : 23-12-2003 13:40 » 

Цитата

for (i = 0; i < 20; i++)
delete pm++;


Ну это уж совсем. Офигительно неправильная операция(извини за резкость- но это ужасная ошибка, делать так как ты предложил).
 Никогда так делать нельзя- перед началом выделенной области и после ее конца находится служебная инфа, в таком случае в роли этой инфы выступят элементы массива. Выделил operator new[](...) - удаляй operator delete[](void*).
Записан
Lex
Специалист

ru
Offline Offline

WWW
« Ответ #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
Специалист

ru
Offline Offline

WWW
« Ответ #12 : 23-12-2003 14:02 » 

Нда, проблема решилась заменой new/delete на
HeapAlloc(GetProcessHeap(), .....)/HeapFree(GetProcessHeap(), .....)

Странно. Исходя из MSDN malloc и new, по идее должны использовать эти же функции.
Записан

Megabyte be with you!
SlavaI
Главный специалист

ru
Offline 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
Специалист

ru
Offline Offline

WWW
« Ответ #14 : 23-12-2003 14:39 » 

SlavaI, все в дебажном варианте. Про переопределение это я знаю, но в все равно должно вызываться HeapAlloc() (хотя я могу быть и не прав). Всякие GlobalAlloc LocalAlloc в Win32 согласно MSDN в итоге вызывают HeapAlloc(). и это сделано для совместимости с 16-битными приложениями.
Единственный возможный вариант это то, что MFC использует разные кучи для каждого модуля. Пойду покопаюсь в исходниках MFC. Улыбаюсь
Записан

Megabyte be with you!
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #15 : 23-12-2003 14:46 » 

Цитата

Пойду покопаюсь в исходниках MFC


И охота тебе в этом копаться Отлично . Как ты дошел до такой жизни- использовать MFC? Проект что ли старый очень?
Записан
Lex
Специалист

ru
Offline Offline

WWW
« Ответ #16 : 23-12-2003 15:07 » 

Цитата

Как ты дошел до такой жизни- использовать MFC? Проект что ли старый очень?

Угу ему ужо лет 5 будет, а то и больше.
В общем в MFC они просто _malloc_dbg() /_free_dbg() вызывают
А те в свою очередь уже занимаются вызовом HeapAlloc()/HeapFree().

Слава, кстати, я менял new на malloc() та же фигня. Ты случаем не в курсе, как эти кучи распределяются по загруженным модулям и основной программе?
Записан

Megabyte be with you!
Mouse
Молодой специалист

ru
Offline Offline

« Ответ #17 : 23-12-2003 16:07 » 

У меня давно было что-то подобное. У меня дело было вот в чем: я пытался удалять указатель дважды, т.е. (на данном примере) первый раз в GetMyStruct(), а второй раз уже в вызывающем модуле непосредственно delete'ом. Проверь эту тему. Конкретно в чем дело, я тогда не копал - исправил и забыл...
Просто смотри, Lex: область видимости переменной pm - функция GetMyStruct(). А ведь по выходе указатель удаляется автоматически! По крайней мере так должно быть. Просто по идее GetMyStruct() возвращает указатель, который по выходе из функции уничтожается, т.е. система считает его = NULL. Слушай, а в основном модуле обработка pm шла корректно?
Записан
Lex
Специалист

ru
Offline Offline

WWW
« Ответ #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
Помогающий

de
Offline Offline
Пол: Мужской

« Ответ #20 : 24-12-2003 07:58 » 

У меня подобная проблема была, и я спрашивал об этом на форуме, но тогда пришли к мнению, что я что-то где упустил. Динамически созданный класс возвращал указатель на выделенный массив, затем класс уничтожался. И начинались такие танцы с бубнами... память то выделялась, то нет. Заказываешь один объем - выделяется, заказываешь меньший(!) - вылетает.
Записан
Lex
Специалист

ru
Offline Offline

WWW
« Ответ #21 : 24-12-2003 10:18 » 

NetRaider, куч несколько. Точнее там все намного хитрее. Достаточно большая пляска идет с выделением виртуальных страниц. И вся эта инфа, кстати, цепляется к выделеному блоку.
Записан

Megabyte be with you!
NetRaider
Гость
« Ответ #22 : 25-12-2003 06:56 » 

Цитата

Достаточно большая пляска идет с выделением виртуальных страниц. И вся эта инфа, кстати, цепляется к выделеному блоку.


Цепляется...  И сохраняется в списке, состоящем из экземпляров _CrtMemBlockHeader. А экземпляров этих списков может быть несколько. Отсюда и проблемы - выделил кусок память - информация о нем сохранилась в списке. Удалять надо и этого же списка, а не из другого.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #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
Специалист

ru
Offline Offline

WWW
« Ответ #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
Специалист

ru
Offline Offline

WWW
« Ответ #27 : 22-01-2004 11:32 » new

Boris Tkach, понятно, что нельзя возникает вопрос почему?
Записан

Megabyte be with you!
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #28 : 22-01-2004 13:14 » 

Lex,  Слушай, я так (или почти так) делал - работало и работает уже года два поэтому и тебе советовал. А вот тепрь сомневатся начал - чую, что-то не то. Правда соблюдены условия:

Цитата: Boris Tkach

при сборке указываются одинаковые 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
Специалист

ru
Offline Offline

WWW
« Ответ #29 : 22-01-2004 18:36 » 

Джон, понял ты правильно. И задача у меня похожая. У меня есть основное окно и куча dll, которые описывают разные типы приемников, загружаемые динамически.

Проблему я решил, но осталось недопонимание причин проблемы.
Мое видение было таково, что все dll грузятся в адресное пространство процесса и память всегда выделяется в адресном пространстве процесса.
Из этого я делал вывод, что все равно где вызывать new и delete(также как malloc и free). Оказалось, что это не так, по крайней мере не всегда.
Вот и хочется понять почему.
Записан

Megabyte be with you!
Страниц: [1] 2  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines