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

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

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

WWW
« : 29-09-2007 17:02 » 

Использую BC++6.

Динамически создаю MDI окна через new TfrmMyForm.

Вот пример обработчика OnClick пункта меню:
Код: (C++)
// MenuItem onClick

    if (!frmMyFrom)
        frmMyFrom = new TfrmMyForm(this);
    else
        frmMyFrom->WindowState = wsNormal;

Окно закрываю так:
Код: (C++)
// MyForm onClose

    frmMyForm = 0;
    Action = caFree;

Я не могу понять по документации, нужно ли мне тут делать delete frmMyForm?
И если нужно, то могу ли я это сделать в обработчике onClose этой формы?

Для модальных окон это проще:
Код: (C++)
    frmMyFrom = new TfrmMyForm(this);
    frmMyForm->ShowModal();
    delete frmMyForm;

Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline 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
Технический
Администратор

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

WWW
« Ответ #2 : 29-09-2007 17:56 » 

Строчка "Action = caFree;" приводит к освобождению памяти, но что именно освобождается - я не знаю.

Я думаю, не стоит искать фичи MFC в VCL - может просто не совпадать. В VCL как-то проще все.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

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


« Ответ #3 : 29-09-2007 18:02 » 

WM_DESTROY есть не только в MFC )
Записан

RXL
Технический
Администратор

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

WWW
« Ответ #4 : 29-09-2007 18:07 » 

Леш, мне совершенно это не интересно. Я спрашиваю конкретику. Про существование сообщений я прекрасно знаю, но вопрос не про это.
Записан

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

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 29-09-2007 18:11 » 

Ром, насколько я помню VCL. Убийство экземляра класса формы забота родительского класса. Ты должен только вызвать метод close твоего класса. Хотя могу уже и не помнить Улыбаюсь
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
RXL
Технический
Администратор

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

WWW
« Ответ #6 : 29-09-2007 18:36 » 

А нет ли какого-нибудь профайлера для BC++6? - Хотелось бы на утечки памяти потестить, а за одно и с уничтожением форм разобраться.
Записан

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

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #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
Технический
Администратор

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

WWW
« Ответ #9 : 01-10-2007 17:55 » new

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
Технический
Администратор

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

WWW
« Ответ #11 : 02-10-2007 06:42 » 

zubr, интересные данные получаются.

Провел серию тестов. Выяснил:
1. Установка caFree приводит к вызову деструктора.
2. delete - тоже, естественно.

Если задать caFree и сделать delete, то деструктор вызывается два раза!
Причем, возврат из ShowModal и вызов delete происходят раньше, чем первый вызов деструктора. На втором вызове деструктора получаю Access Violation. К сожалению, это не говорит об освобождении памяти объектом...
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines