Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 09.01.2013, 11:48   #1
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию TStringList и Oбъекты. При уничтожении StringLIst - теряет обьекты?

Доброго времени суток!

Есть некий наследник TStringList он хранит строки, и с каждой строкой ассоциирован объект N.

Вот такой стэк вызова выдает MadExcept:
Код:
00407e42 +06 DogsShow.exe System          15046  +4 TObject.Free
00647db4 +2c DogsShow.exe clDogSexList       63  +1 TDogSexObj.Destroy
00407e44 +08 DogsShow.exe System          15046  +4 TObject.Free
0051d446 +b2 DogsShow.exe System.Classes   6488 +19 TStringList.Destroy
006480f2 +1a DogsShow.exe clDogSexList      129  +1 TDogSexList.Destroy
00407e44 +08 DogsShow.exe System          15046  +4 TObject.Free
00648482 +1e DogsShow.exe mMain              40  +1 TDM.DataModuleDestroy
00532ecf +2b DogsShow.exe System.Classes  16724  +3 TDataModule.DoDestroy
00532da3 +27 DogsShow.exe System.Classes  16693  +4 TDataModule.BeforeDestruction
004084e9 +09 DogsShow.exe System          16310 +10 @BeforeDestruction
00532dae +06 DogsShow.exe System.Classes  16697  +0 TDataModule.Destroy
0053110b +57 DogsShow.exe System.Classes  15673 +11 TComponent.DestroyComponents
006307a5 +35 DogsShow.exe Vcl.Forms        2142  +9 DoneApplication
0044e701 +21 DogsShow.exe System.SysUtils  5039  +6 DoExitProc
004098dd +65 DogsShow.exe System          21377 +44 @Halt0
0069d790 +88 DogsShow.exe DogsShow           31  +8 initialization
75933c43 +10 kernel32.dll                           BaseThreadInitThunk
Вот такой код:
Цитата:
type
TDogSexObj = class(TObject)
// :D Самомуdo смешно, но да, интуитивно понятные имена это хорошо.
public
SexName: string;
SexPriority: Integer;
Edit: TEdit;
LI: TListItem;
procedure OnEditChange(Sender: TObject);
procedure OnEditExit(Sender: TObject);
constructor Create(sName: string; iPriority: Integer); overload;
destructor Destroy; override;
end;

type
TDogSexList = class(TStringList)
private
fVisible: Boolean;
fLV: TListView;
procedure SetVisible(const Value: Boolean);
public
property ListView: TListView read fLV write fLV;
property Visible: Boolean read fVisible write SetVisible;
procedure Delete(aIndex: Integer); overload; override;
procedure Clear; overload; override;
function PriorityExists(aInt: Integer): Boolean;
function AddSex(aStr: string; aPriority: Integer): Integer;
constructor Create; overload;
destructor Destroy; override;
end;

implementation

{ TDogSexObj }

constructor TDogSexObj.Create(sName: string; iPriority: Integer);
begin
inherited Create;
SexPriority := 0;
SexName := '';
SexName := sName;
SexPriority := iPriority;
Edit := TEdit.Create(nil);
Edit.NumbersOnly := True;
Edit.Visible := False;
Edit.OnChange := OnEditChange;
Edit.OnExit := OnEditExit;
end;

destructor TDogSexObj.Destroy;
begin
{
Тут возникает AV при закрытии.
Это событие возникает только 1 раз.
И в этот раз, Edit - не существует.
Тут 2я утечка памяти.
}
FreeAndNil(Edit);
inherited;
end;

{ TDogSexList }

function TDogSexList.AddSex(aStr: string; aPriority: Integer): Integer;
var
Data: TDogSexObj;
iObj: Integer;
begin
iObj := -1;
Data := TDogSexObj.Create(aStr, aPriority);
iObj := AddObject(aStr, Data);
Data := TDogSexObj(Objects[iObj]);
if fVisible and Assigned(fLV) then
begin
LI := fLV.Items.Add;
LI.Caption := Data.SexName;
LI.SubItems.Add(IntToStr(Data.SexPr iority));
Data.Edit.Parent := fLV;
Data.LI := LI;
LI.Data := Data;
end;
Result := iObj;
end;

constructor TDogSexList.Create;
begin
inherited Create(True); //<-Тут утечка памяти. Как исправить?
end;

destructor TDogSexList.Destroy;
begin
inherited;
end;
Итого мы видим:
1. При разрушении TStringList, его объекты напрочь потеряли свои TEdit и в деструкторе класса ошибка и утечка памяти.
2. При уничтожении объекта и создании контейнера - возникает утечка памяти.

Как это лечить? И почему это происходит?

Даже поместил Edit в protected секцию класса - ничего не изменилось. Он все равно исчезает неведомо куда.

Последний раз редактировалось Человек_Борща; 09.01.2013 в 11:55.
Человек_Борща вне форума Ответить с цитированием
Старый 09.01.2013, 12:06   #2
phomm
personality
Старожил
 
Аватар для phomm
 
Регистрация: 28.04.2009
Сообщений: 2,882
По умолчанию

Код:
Data.Edit.Parent := fLV;
Возможно, тут эдит становится под опеку листвью, а уничтожающийся листвью чистит эдит и вызов FreeAndNil(Edit) уже обращается по недоступной памяти.

Мне непонятно это
Код:
inherited Create(True);
У стринглиста не было такого конструктора в иерархии, с обжектлистом не путаете? Ну, я правда допускаю, что это в дельфи с 2009 версии появилось.
Также непонятно
Код:
Data := TDogSexObj(Objects[iObj]);
по идее на тот момент в Data уже лежит то же самое. По идее, некритично, просто непонятно зачем.
Про утечки я бы ещё в сторону листвью поглядел. Ну и банальное - нигде у объекта не вызываете креэйт вместо класса ?
phomm вне форума Ответить с цитированием
Старый 09.01.2013, 12:22   #3
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Цитата:
У стринглиста не было такого конструктора в иерархии, с обжектлистом не путаете? Ну, я правда допускаю, что это в дельфи с 2009 версии появилось.
Правильно допускаете.
Код:
constructor TStringList.Create;
begin
  inherited Create;
end;

constructor TStringList.Create(OwnsObjects: Boolean);
begin
  inherited Create;
  FOwnsObject := OwnsObjects;
end;
FOwnsObject - Говорит о том, что класс будет жить с объектами и контролировать их жизненный цикл.

Цитата:
нигде у объекта не вызываете креэйт вместо класса ?
Нет, нигде больше. Класс управляет этим самым ListView(Добавление/удаление).

Цитата:
Возможно, тут эдит становится под опеку листвью, а уничтожающийся листвью чистит эдит и вызов FreeAndNil(Edit) уже обращается по недоступной памяти.
Вы оказались правы! Как только я убрал свой FreeAndNil - проблема разрешилась и утечек памяти тоже нет. Весов++ за идею =)

Получается как только объект получает родителя, то уже родитель контролирует жизненный цикл объекта, а список - просто место хранения.

Цитата:
по идее на тот момент в Data уже лежит то же самое. По идее, некритично, просто непонятно зачем.
Data перемещается на хранение в список, но сам - локальная переменная, а мне нужен уже объект списка а не лок. переменная.
Поэтому я таким образом переопределяю содержимое этой переменной из локальных данных, на данные уже из объекта в списке.
Это избавляет от некоторых проблем.

Последний раз редактировалось Человек_Борща; 09.01.2013 в 12:28.
Человек_Борща вне форума Ответить с цитированием
Старый 09.01.2013, 12:39   #4
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Глупая мешанина бизнес логики, структур хранения и компонент отображения... переделать!
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 09.01.2013, 13:41   #5
phomm
personality
Старожил
 
Аватар для phomm
 
Регистрация: 28.04.2009
Сообщений: 2,882
По умолчанию

Slym, Я тоже хотел пожаловаться на некоторую "кашу", но "интуитивно понятные имена" меня покорили и я воздержался

Человек_Борща, не обессудьте, с поздними версиями дельфи редко работаю, обычно всё 7 и 2007, хотя, теоретически мог бы найти и в онлайн-справке.
Ну, а насчёт родителей владельцев формовых компонент я уже где-то в инете с кем-то обсуждал, тогда как раз докопались до кода в ВСЛ где перент как и овнер имеет список компонент и сам их чистит, как видите, пригодилось ))
Ну, а насчёт Data - это же указатель, какая разница локальная переменная или где-то там ) на данные он указывает одни и те же ) ведь именно адрес этих данных обрабатывается, а не адрес самой переменной указателя )

Последний раз редактировалось phomm; 09.01.2013 в 13:44.
phomm вне форума Ответить с цитированием
Старый 09.01.2013, 13:56   #6
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Slym, И как можно проще?
Суть в том что этот список - часть большого проекта, и форма редактора рождается только тогда, когда она нужна.
ListView - всего лишь способ удобного отображения, и не менее удобного редактирования.


Цитата:
Ну, а насчёт Data - это же указатель, какая разница локальная переменная или где-то там ) на данные он указывает одни и те же ) ведь именно адрес этих данных обрабатывается, а не адрес самой переменной указателя )
Спасибо, это все упрощает. просто закралась мысль, что данные из локальной переменной исчезает после её уничтожения. Хотя с чего бы? Но все равно тревожно было.


Проект: формирование каталогов для выставки собак. Это насчет интуитивно понятных форм.

Последний раз редактировалось Человек_Борща; 09.01.2013 в 14:00.
Человек_Борща вне форума Ответить с цитированием
Старый 09.01.2013, 14:12   #7
phomm
personality
Старожил
 
Аватар для phomm
 
Регистрация: 28.04.2009
Сообщений: 2,882
По умолчанию

Цитата:
Сообщение от Человек_Борща Посмотреть сообщение
Slym, И как можно проще?
Хоть не мне адресовано, но скажу.
Возможно, не проще, но методика для разработки подобного существует. В своё время изучал по статьям на рсдн , вводную дам вот эту http://www.rsdn.ru/article/patterns/patterns.xml а там и далее может куда выйдете.
Это не истина в последней инстанции и вообще дело долгое, но я считаю в перспективе очень хороший подход.
Кстати, где-то должны были остаться эксперименты, навеяные этой статьёй и плюс до кучи по БД, могу скинуть.
phomm вне форума Ответить с цитированием
Старый 09.01.2013, 14:14   #8
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Мне интересно - какая такая необходимость редактирование в субитемах ListView организовывать, плодя при этом тучу TEdit? Тот же StringGrid спокойно и без проблем с этой задачей справится
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 09.01.2013, 14:42   #9
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Цитата:
Сообщение от Человек_Борща Посмотреть сообщение
Slym, И как можно проще?
Суть в том что этот список - часть большого проекта, и форма редактора рождается только тогда, когда она нужна.
ListView - всего лишь способ удобного отображения, и не менее удобного редактирования.
Форма редактора рождается по требованию, а контролы редактора создаются всегда?
и про секс - он либо есть либо его нет true/false м/ж m/f
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 09.01.2013, 14:59   #10
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Цитата:
и про секс - он либо есть либо его нет true/false м/ж m/f
У вас в паспорте есть поле sex. В моем случае это пол Хотя... Заменю-ка я это на Gender.

Цитата:
Форма редактора рождается по требованию, а контролы редактора создаются всегда?
Угу. Это переделаю.

Цитата:
Мне интересно - какая такая необходимость редактирование в субитемах ListView организовывать, плодя при этом тучу TEdit? Тот же StringGrid спокойно и без проблем с этой задачей справится
Таблицы меня чем-то отпугивают. ListView приятнее как-то.
Человек_Борща вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
DSL-модем теряет Интернет при нагрузке Arigato Компьютерное железо 6 25.09.2012 22:28
Использование Self.Handle при создании и уничтожении компонента spamer Общие вопросы Delphi 19 11.03.2010 00:51
Ошибка AV при уничтожении объектов из модулей(dll) puga555 Общие вопросы Delphi 4 08.01.2010 22:14
Обьекты при компиляции prod87 Общие вопросы Delphi 4 28.10.2009 00:37