RXL
|
|
« : 29-09-2007 17:02 » |
|
Использую BC++6. Динамически создаю MDI окна через new TfrmMyForm. Вот пример обработчика OnClick пункта меню: // MenuItem onClick
if (!frmMyFrom) frmMyFrom = new TfrmMyForm(this); else frmMyFrom->WindowState = wsNormal; Окно закрываю так: // MyForm onClose
frmMyForm = 0; Action = caFree; Я не могу понять по документации, нужно ли мне тут делать delete frmMyForm? И если нужно, то могу ли я это сделать в обработчике onClose этой формы? Для модальных окон это проще: frmMyFrom = new TfrmMyForm(this); frmMyForm->ShowModal(); delete frmMyForm;
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #1 : 29-09-2007 17:29 » |
|
RXL, как в борланде, не ведаю, а в MFC удобно такие диалоги удалять в виртуальной функции PostNcDestroy удаляемого окна если создали через new, то закрываем окно исключительно вызовом DestrowWindow() окна (когда пользователь закрывает окно крестиком - оно вызовется само) void CMyDialog::PostNcDestroy() { CDialog::PostNcDestroy(); delete this; }
возможно, это можно сделать и в конце обработчика WM_DESTROY
|
|
« Последнее редактирование: 29-09-2007 17:33 от Алексей1153++ »
|
Записан
|
|
|
|
RXL
|
|
« Ответ #2 : 29-09-2007 17:56 » |
|
Строчка "Action = caFree;" приводит к освобождению памяти, но что именно освобождается - я не знаю.
Я думаю, не стоит искать фичи MFC в VCL - может просто не совпадать. В VCL как-то проще все.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #3 : 29-09-2007 18:02 » |
|
WM_DESTROY есть не только в MFC )
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #4 : 29-09-2007 18:07 » |
|
Леш, мне совершенно это не интересно. Я спрашиваю конкретику. Про существование сообщений я прекрасно знаю, но вопрос не про это.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Finch
Спокойный
Администратор
Online
Пол:
Пролетал мимо
|
|
« Ответ #5 : 29-09-2007 18:11 » |
|
Ром, насколько я помню VCL. Убийство экземляра класса формы забота родительского класса. Ты должен только вызвать метод close твоего класса. Хотя могу уже и не помнить
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
RXL
|
|
« Ответ #6 : 29-09-2007 18:36 » |
|
А нет ли какого-нибудь профайлера для BC++6? - Хотелось бы на утечки памяти потестить, а за одно и с уничтожением форм разобраться.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Finch
Спокойный
Администратор
Online
Пол:
Пролетал мимо
|
|
« Ответ #7 : 30-09-2007 22:24 » |
|
Вот тут http://www.relisoft.com/book/tech/9new.html я наткнулся на трейсер утечки памяти. Правда он адаптирован под Visual Studio C++. Но так думаю, его можно подправить под билдер. Код поключается к проекту. DebugNew.h#if !defined DEBUGNEW_H
#define DEBUGNEW_H
#pragma warning (disable:4786)
void * operator new (size_t size, char const * file, int line);
void operator delete (void * p, char const * file, int line);
void * operator new (size_t size);
void operator delete (void * p);
#include <map>
class Tracer
{
private:
class Entry
{
public:
Entry (char const * file, int line)
: _file (file), _line (line)
{}
Entry ()
: _file (0), _line (0)
{}
char const * File () const { return _file; }
int Line () const { return _line; }
private:
char const * _file;
int _line;
};
class Lock
{
public:
Lock (Tracer & tracer)
: _tracer (tracer)
{
_tracer.lock ();
}
~Lock ()
{
_tracer.unlock ();
}
private:
Tracer & _tracer;
};
typedef std::map<void *, Entry>::iterator iterator;
friend class Lock;
public:
Tracer ();
~Tracer ();
void Add (void * p, char const * file, int line);
void Remove (void * p);
void Dump ();
static bool Ready;
private:
void lock () { _lockCount++; }
void unlock () { _lockCount--; }
private:
std::map<void *, Entry> _map;
int _lockCount;
};
extern Tracer NewTrace;
#endif
DebugNew.cpp#include "debugnew.h"
#include <sstream>
#include <new>
#include <windows.h> // OutputDebugString
#if !defined NDEBUG
bool Tracer::Ready = false;
void * operator new (size_t size, char const * file, int line)
{
void * p = malloc (size);
if (Tracer::Ready)
NewTrace.Add (p, file, line);
return p;
}
void operator delete (void * p, char const * file, int line)
{
if (Tracer::Ready)
NewTrace.Remove (p);
free (p);
}
void * operator new (size_t size)
{
void * p = malloc (size);
if (Tracer::Ready)
NewTrace.Add (p, "?", 0);
return p;
}
void operator delete (void * p)
{
if (Tracer::Ready)
NewTrace.Remove (p);
free (p);
}
Tracer::Tracer ()
: _lockCount (0)
{
Ready = true;
}
Tracer::~Tracer ()
{
Ready = false;
Dump ();
}
void Tracer::Add (void * p, char const * file, int line)
{
if (_lockCount > 0)
return;
Tracer::Lock lock (*this);
_map [p] = Entry (file, line);
}
void Tracer::Remove (void * p)
{
if (_lockCount > 0)
return;
Tracer::Lock lock (*this);
iterator it = _map.find (p);
if (it != _map.end ())
{
char const * file = it->second.File ();
int line = it->second.Line ();
_map.erase (it);
}
}
void Tracer::Dump ()
{
if (_map.size () != 0)
{
::OutputDebugString ("*** Memory leak(s):\n");
for (iterator it = _map.begin (); it != _map.end (); ++it)
{
char const * file = it->second.File ();
int line = it->second.Line ();
int addr = reinterpret_cast<int> (it->first);
std::stringstream out;
//out << "0x" << std::hex << addr << ": "
// << file << ", line " << std::dec << line << std::endl;
char buffer1 [10];
char buffer2 [8];
out << "0x" << itoa (addr, buffer1, 16) << ": "
<< file << ", line " << itoa (line, buffer2, 10) << std::endl;
::OutputDebugString (out.str ().c_str ());
}
::OutputDebugString ("\n");
}
}
#endif
Я конечно понимаю, что это кастыль. Но пока что можно использовать.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
zubr
Гость
|
|
« Ответ #8 : 01-10-2007 06:38 » |
|
Delete в данном случае делать не нужно. Вот что написано в Help: C++ syntax:
enum TCloseAction { caNone, caHide, caFree, caMinimize }; typedef void __fastcall (__closure *TCloseEvent)(System::TObject* Sender, TCloseAction &Action); __property TCloseEvent OnClose = {read=FOnClose, write=FOnClose, stored=IsForm};
Description
Use OnClose to perform special processing when the form closes. The OnClose event specifies which event handler to call when a form is about to close. The handler specified by OnClose might, for example, test to make sure all fields in a data-entry form have valid contents before allowing the form to close.
A form is closed by the Close method or when the user chooses Close from the form's system menu.
The TCloseEvent type points to a method that handles the closing of a form. The value of the Action parameter determines if the form actually closes. These are the possible values of Action:
Value Meaning
caNone The form is not allowed to close, so nothing happens. caHide The form is not closed, but just hidden. Your application can still access a hidden form. caFree The form is closed and all allocated memory for the form is freed. caMinimize The form is minimized, rather than closed. This is the default action for MDI child forms.
If a form is an MDI child form, and its BorderIcons property is biMinimize, then the default Action is caMinimize. If a MDI child form does not have these settings, the default Action is caNone, meaning that nothing happens when the user attempts to close the form.
If a form is an SDI child form, Action defaults to caHide.
To close the form and free it in an OnClose event, set Action to caFree.
Note: When the application shuts down, the main form receives an OnClose event, but any child forms do not receive the OnClose event.
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #9 : 01-10-2007 17:55 » |
|
zubr, хорошо, тогда такое сравнение:
1. Создаю через new, запускаю модально, потом удаляю через delete. При этом в onClose устанавливаю в caFree. Ошибок нет.
2. Создаю через new, запускаю как MDI. в onClose устанавливаю в caFree. Ошибок нет.
Да, во втором случае форма помечена как MDIChild - разница таки есть. Просто у меня нет уверенности, что освободилась память, занятая new.
Finch, спасибо - штука интересная. Только не думаю, что я ею воспользуюсь - просто не удобно. У меня исходники проекта весят больше мегабайта - стремно такие подмены встраивать - могут вылезти боком. Впрочем, можно попробовать проделать эксперимент на отдельном пустом проекте.
|
|
« Последнее редактирование: 01-10-2007 18:47 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
zubr
Гость
|
|
« Ответ #10 : 02-10-2007 04:14 » |
|
RXL, простой тест. в обработчике Destroy, создаваемой формы, пропиши какой нибудь MessageBox (или просто смотри в отладчике). А теперь, вызывай Delete - всегда будет вызываться Destroy. Теперь пробуй вызывай Close, если Action!=caFree, то Destroy не вызывается, то есть память не освобождается. З.Ы. Стройки сейчас под рукой нет, но в Delphi так.
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #11 : 02-10-2007 06:42 » |
|
zubr, интересные данные получаются.
Провел серию тестов. Выяснил: 1. Установка caFree приводит к вызову деструктора. 2. delete - тоже, естественно.
Если задать caFree и сделать delete, то деструктор вызывается два раза! Причем, возврат из ShowModal и вызов delete происходят раньше, чем первый вызов деструктора. На втором вызове деструктора получаю Access Violation. К сожалению, это не говорит об освобождении памяти объектом...
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
|