Re[3]: Удаление динамически выделенной памяти
От: Кодт Россия  
Дата: 06.05.13 08:15
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Удаляется память под объекты только в единственном месте, в одной функции, реентер которой регулируется мьютексом, т.е. запустить ее второй раз не удастся ни в другом потоке, ни в этом же, пока она не закончит работу и не освободит мьютекс.


Мьютекс не защищает от однопоточного реентера. Тут нужны гарантии иного рода — что функция не будет вызвана рекурсивно (собственно, реентер — это патологическая рекурсия, которую нужно или избежать, или нейтрализовать).

И кстати, мьютексы в оконном потоке, без полного понимания, что там происходит, — это такая богатая кладовая дедлоков...
Потому что, кроме непосредственно пользовательского мьютекса, там ещё незримо присутствует глобальный синхрообъект — очередь сообщений.
Так что мьютексы — исключительно для огораживания критических секций кода: прочитать что-нибудь из контейнера, положить что-нибудь в контейнер, — но ни в коем случае не вызывать методы элементов контейнера, которые устроят лавину вызовов и посылок сообщений.

А>Объекты данного класс присоединяется к событиям открытых окон IE через DIID_DWebBrowserEvents2, соответственно сколько окон(вкладок) столько и объектов. Удаление объекта по логике работы программы происходит после анализа открытых окон IE и сравнения их с хранимыми в контейнере, соответственно если окна нет, а в контейнере оно есть, то удаляется память и удаляется элемент контейнера.


А>Возникают следующие вопросы:

А>1) почему деструктор вызывается дважды
Собственно, трижды.

А>2) каким образом и кем деструктор может вызываться, если он точно вызывается не кодом, так как это делается потом


Брекпоинты — наше всё. Поймать все три момента и посмотреть, откуда инициировано действие.

Думаю, что там стоит какое-нибудь m_bAutoDelete, что заставляет фреймворк удалять ненужные, по его мнению, объекты.
Например, самоликвидация объекта CWinThread по заверешении его Run().

А>3) "Отдавать уничтожение CCmdTarget'ов на откуп деструкторам (их самих или их владельцев) самонадеянно. Там и виндоуз выполняет обряд умерщвления, и MFC к нему прикладывается... в общем, я сейчас не готов развернуть тему, что делать и кого виновать (для этого мне надо ставить винды и студию, и вспоминать былое)." Поясните пожалуйста это более подробно, может надо совершить какие-то действия или...что?


У окон есть событие WM_NCDESTROY, после которого окно уже ни в каком виде не существует, и его объект-представитель — если он больше не нужен, как, например, CView какой-нибудь, можно уничтожать. У потоков такой ключевой момент — завершение Run().
Какие там ещё разновидности CCmdTarget бывают...

А>Часть лога программы где видно вызов деструкторов (неожиданно) и удаление согласно логике работы программы ( где и ожидается удаление):


А>12:13:50 5e4 OnIETimer Add new web browser

А>12:13:50 5e4 OnIETimer Add new web browser if
А>12:13:50 5e4 EA5BE0 OnIETimer new CWebBrowser2 — выделена память и создан объект класса CWebBrowser2

Код в студию!

<>
А>12:13:50 5e4 EA5BE0 Checking interface pointer — 1 вызов деструктора

Код и стек в студию! Что это за загадочное "Checking interface pointer"?

А>12:13:50 5e4 EA5BE0 Start Reset function — работа по условию if при 1 вызове деструктора (в функции самого деструктора)


Код и стек в студию!

А>12:13:50 5e4 EA5BE0 Checking interface pointer — 2 вызов деструктора (условие if уже не сработало)


Код и стек в студию!
Может быть, ещё в первый раз надо было предварительно обнулить указатель или иным способом отвязаться от объекта-владельца.
А то он так и будет дёргать деструктор, пока не надоест.

А>12:13:51 128c send_data_thread_delay_175000

А>12:13:51 128c ServiceDelaySetTimer
А>12:13:51 128c send_data_thread Mutex closed
А>12:14:04 5e4 OnIETimer
А>12:14:04 5e4 OnIETimer Mutex created
А>12:14:04 5e4 OnIETimer Get openning IE windows
А>12:14:04 5e4 OnIETimer Delete cycle start — старт цикла удаления невалидный объектов (данных окон IE уже нет)
А>12:14:04 5e4 OnIETimer m_oAdvisedWebBrowser2 count is 3
А>12:14:04 5e4 OnIETimer m_oAdvisedWebBrowser2 return 2 element
А>12:14:04 5e4 EA5BE0 OnIETimer We going to delete memory — попытка вызвать delete pWebBrowser2, 3 вызов деструктора

Код в студию! Чисто для порядка.
Не в смысле — for(int i=nCnt-1;....) а то место, где принимается решение удалять ненужные объекты.
Перекуём баги на фичи!
Re: Удаление динамически выделенной памяти
От: visual_wind  
Дата: 08.05.13 07:09
Оценка:
Здравствуйте, kupaloff,

Есть предположение, что delete не нужно вызывать совем, это сделает за вас фреймворк MFC. Вы работаете с событиями интернет эксплорера через класс-наследник от CCmdTarget. Эта работа идет через СОМ-интерфейсы, и CCmdTarget, который уже содержит поддержку интерфейса IDispatch, автоматически вызовет нечто наподобие delete this в OnFinalRelease(), удаляя сам себя по обнулению счетчика ссылок.

Я писал на MFC достаточно давно и сейчас точно не скажу. Попробуйте для начала почитать статью здесь
Автор(ы): Тимофей Чадов
, также можете посмотреть пример здесь. И, похоже, вот здесь у человека была похожая проблема, может, вам помогут ответы.
Re[2]: Удаление динамически выделенной памяти
От: wvoquine  
Дата: 12.05.13 05:07
Оценка:
Здравствуйте, Кодт, Вы писали:

К>// вторая фаза: сжимаем исходный массив (повода для реентера ещё нет...)

К>for(int i=n-1; i>=0; --i)
К> if(!arr[i]) arr.RemoveAt(i);


А для CArray есть swap с другим CArray? А то ведь можно было бы заполнить временный массив с зарезервированной заранее памятью и свопнуться с ним, как это можно было бы сделать для vector.
To be is to be the value of a variable
Re[3]: Удаление динамически выделенной памяти
От: Scrotum  
Дата: 20.05.13 16:41
Оценка:
Здравствуйте, kupaloff, Вы писали:

Купалов! Нееште карри перед сном!!!

K>вот код выделения памяти:


K>
K>typedef CArray<CWebBrowser2*, CWebBrowser2*> CAdvisedWebBrowser2;
K>CAdvisedWebBrowser2 m_oAdvisedWebBrowser2;

K>...

K>TRY
K>{

K>    ...

K>    CWebBrowser2* pWebBrowser2 = NULL;
K>    pWebBrowser2 = new CWebBrowser2(this);
K>    if(NULL != pWebBrowser2)
K>    {
K>        m_oAdvisedWebBrowser2.Add(pWebBrowser2);
K>    }

K>    ...
K>}
K>CATCH(CMemoryException, ex)
K>{
K>    TCHAR cause[MAX_PATH] = {0};

    ex->>GetErrorMessage(cause, MAX_PATH);

K>    TCHAR log_mes[100 + MAX_PATH] = {0};
K>    sprintf(log_mes, _T("OnIETimer CMemoryException %s "), cause);
K>    AddToLog(log_mes);

K>    AfxAbort();
K>}
K>END_CATCH
K>


K>CWebBrowser2* — это класс
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.