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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 22.08.2011, 11:12   #1
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию EStackOverflow в собсвенном классе

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

Переписываю в программе некоторые вещи, и их надо реализовывать отдельным классом.

Сам класс:
Код:
unit SFLFilesListClass;

interface

uses Windows, SysUtils, Classes, StdCtrls, ComCtrls, sListView;

const
  Delim = ':';

type
  TSFLFile = class(TObject)
    SearchByMD5: Boolean;
    FilesName: string;
    FileMD5: string;
  end;

type
  TSFLList = Class(TList)
  private
    fListView: TsListView;
    TS: TStringList;
    function GetFile(Indx: Integer): TSFLFile;
  public
    constructor Create;
    destructor Destroy; override;
    property Records[Indx: Integer]: TSFLFile read GetFile;
    procedure AddRecordToLV(aSFLFileRec: TSFLFile);
    procedure DeleteRecord(Indx: Integer);
    property ListView: TsListView read fListView write fListView;
    procedure SaveToFile(aFileName: string);
    function GetSFLFileSearchState(aParam: Boolean): string;
  End;

implementation

{ TSFLList }

function TSFLList.GetSFLFileSearchState(aParam: Boolean): string;
begin
  if aParam then
    Result := 'h' // По контрольной сумме
  else
    Result := 'n'; // По имени
end;

procedure TSFLList.AddRecordToLV(aSFLFileRec: TSFLFile);
var
  LI: TListItem;
begin
  with fListView do
  begin
    Add(aSFLFileRec);
    LI := Items.Add;
    LI.Checked := aSFLFileRec.SearchByMD5;
    LI.SubItems.Add(aSFLFileRec.FilesName);
    LI.SubItems.Add(aSFLFileRec.FileMD5);
  end;
end;

constructor TSFLList.Create;
begin
  TS := TStringList.Create;
end;

procedure TSFLList.DeleteRecord(Indx: Integer);
begin
  fListView.Items.Delete(Indx); // Удаление визуально
  Records[Indx].Free; // Освобождение обьекта
  Delete(Indx); // Удаляем из списка         <- ошибка вылетает здесь
end;

destructor TSFLList.Destroy;
var
  i: Integer;
begin
  for i := Count -1 downto 0 do
  begin
    DeleteRecord(i); // Необходимо чтобы память не текла
  end;
  FreeAndNil(TS);
  inherited;
end;

function TSFLList.GetFile(Indx: Integer): TSFLFile;
begin
  Result := Records[Indx];
end;

procedure TSFLList.SaveToFile(aFileName: string);
var
  i: Integer;
begin
  for i := Count -1 downto 0 do
  begin
    TS.Add(Records[i].FilesName + Delim + GetSFLFileSearchState
      (Records[i].SearchByMD5) + Delim + Records[i].FileMD5);
  end;
  TS.SaveToFile(aFileName);
end;

end.

Вот ошибка:
Код:
compiled with     : Delphi XE
madExcept version : 3.0m
callstack crc     : $c81aebe4, $4989c9d5, $4989c9d5
exception number  : 1
exception class   : EStackOverflow
exception message : Stack overflow.

main thread ($b18):
006c46ca +06 SFLGenerator.exe SFLFilesListClass 92 +0 TSFLList.GetFile
006c46d6 +12 SFLGenerator.exe SFLFilesListClass 93 +1 TSFLList.GetFile
006c4636 +26 SFLGenerator.exe SFLFilesListClass 75 +2 TSFLList.DeleteRecord
006c4676 +26 SFLGenerator.exe SFLFilesListClass 85 +3 TSFLList.Destroy
006c5119 +15 SFLGenerator.exe MainFormUnit      88 +1 TMainForm.FormDestroy
006ce22f +5f SFLGenerator.exe SFLGenerator      19 +6 initialization

disassembling:
006c46c4    public SFLFilesListClass.TSFLList.GetFile:  ; function entry point
006c46c4 92   push    ebp
006c46c5      mov     ebp, esp
006c46c7      add     esp, -$c
006c46ca    > mov     [ebp-8], edx
006c46cd      mov     [ebp-4], eax
006c46d0 93   mov     edx, [ebp-8]
006c46d3      mov     eax, [ebp-4]
006c46d6      call    public SFLFilesListClass.TSFLList.GetFile
006c46d6
006c46db      mov     [ebp-$c], eax
006c46de 94   mov     eax, [ebp-$c]
006c46e1      mov     esp, ebp
006c46e3      pop     ebp
006c46e4      ret
Создаю обьект TSFLList, и заполняю элементами TSFLFile, что в общем-то успешно. Но вот деструктор нормально не выполняется. Обьекты TSFLFile класса TObject, и сами они себя тоже не прибьют(Иначе EMemoryLeak). Их нужно руками прибивать, что собственно делает цикл по обьектами и вызов DeleteRecord.

В destructor'е выполняется deleterecord в котором вызывается стандартный метод delete из TList. Собственно тут и происходит ошибка.

Но эта ошибка откровенно задолбала. Укажите пожалуйста на причину ошибки....

Заранее благодарен.

Последний раз редактировалось Человек_Борща; 22.08.2011 в 11:18.
Человек_Борща вне форума Ответить с цитированием
Старый 22.08.2011, 11:26   #2
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Тяжело вместо компилятора, но что бросилось в глаза сразу - отсутствие inherited в конструкторе
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 22.08.2011, 11:34   #3
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

Код:
constructor TSFLList.Create;
begin
  inherited; // !!!!!!!!!!!!!!!!!!!
  TS := TStringList.Create;
end;
И разумней было бы выбрать предком для TSFLList не TList, а TObjectList, тогда бы не пришлось страдать явной деструкцией объектов в своем списочном контеунере - TObjectList умеет сам , т.е. неявно, разрушать объекты, фигурирующие в списке.
mss вне форума Ответить с цитированием
Старый 22.08.2011, 11:35   #4
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Его в конструкторе нужно вызывать до моего кода или после?

Ну почему же. Модуль полный.
реализация как 2 пальца=):
Код:
uses SFLFilesListClass;

var
  FilesList: TSFLList;

{$R *.dfm}

procedure TMainForm.BrowseFilesDirBtnClick(Sender: TObject);
begin
  if PathDlg.Execute then
  begin
    FilesDirEdit.Text := IncludeTrailingPathDelimiter(PathDlg.Path);
  end;
end;

procedure TMainForm.BrowseSaveToDirBtnClick(Sender: TObject);
begin
  if SaveDlg.Execute then
  begin
    SaveToDirEdit.Text := SaveDlg.FileName;
  end;
end;

procedure TMainForm.DoneBtnClick(Sender: TObject);
begin
FilesList.SaveToFile(SaveToDirEdit.Text);
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  FilesList := TSFLList.Create;
  FilesList.ListView := FilesLV;
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  FilesList.Destroy;
end;

procedure TMainForm.MExitClick(Sender: TObject);
begin
  Close;
end;

procedure TMainForm.StartBtnClick(Sender: TObject);
var
  Test: TSFLFile;
begin
  Test := TSFLFile.Create;
  Test.SearchByMD5 := True;
  Test.FilesName := 'TestOneFile';
  Test.FileMD5 := '1234';
  FilesList.AddRecordToLV(Test);
end;
Нужен ListView с Checkboxes:=true; и 3-я колонками.

только в самом классе TsListView заменить на TListView и убрать из uses модуль sListView

__ADD__

mss, тебе цены нет=) Давот незадачка. В каком модуле этот TobjectList мой xe-xe не находит его.

__ADD__

Открыл справку. Данный TObjectList лежит себе в странном Contnrs модуле.

Последний раз редактировалось Человек_Борща; 22.08.2011 в 11:40.
Человек_Борща вне форума Ответить с цитированием
Старый 22.08.2011, 11:39   #5
JTG
я получил эту роль
Старожил
 
Аватар для JTG
 
Регистрация: 25.05.2007
Сообщений: 3,694
По умолчанию

"<- ошибка вылетает здесь" при переполнении стека абсолютно бесполезно: вылетает-то оно тут, а стек забил кто-то раньше. TsListView это дерево какое-то? Бряк на fListView.Items.Delete(Indx) и тыкать F7/F8.

Вообще дженериками очень удобно в списки всякую гадость организовывать.
пыщь

Последний раз редактировалось JTG; 22.08.2011 в 11:41.
JTG вне форума Ответить с цитированием
Старый 22.08.2011, 11:43   #6
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

в конструкторе до вашего кода, в деструкторе после.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 22.08.2011, 11:45   #7
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

Цитата:
Его в конструкторе нужно вызывать до моего кода или после?
В данной реализации по барабану - можно до, можно и после.
Но в подавляющем большинстве случаев правилом "правильного" тона является вызов конструирующего метода предка ДО конструирования своего объекта.

Цитата:
мой xe-xe не находит его
Твой "хе-хе" должен научиться пользоваться встроенной справкой и встроенным в IDE поиском.
А TObjectList находится в contnrs.pas
mss вне форума Ответить с цитированием
Старый 22.08.2011, 11:52   #8
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Спасибо. Проблемы с деструктором отвалились. Ошибка отехала в другое место. Теперь она в коде:
Код:
procedure TSFLList.SaveToFile(aFileName: string);
var
  i: Integer;
begin
  for i := Count -1 downto 0 do
  begin
    TS.Add(Records[i].FilesName + Delim + GetSFLFileSearchState
      (Records[i].SearchByMD5) + Delim + Records[i].FileMD5);
  end;
  TS.SaveToFile(aFileName);
end;
JTG: Ну да. Нашёл свою же ошибку тут:
Код:
procedure TSFLList.AddRecordToLV(aSFLFileRec: TSFLFile);
var
  LI: TListItem;
begin
  with fListView do
  begin
    Add(aSFLFileRec);
    LI := Items.Add;
    LI.Checked := aSFLFileRec.SearchByMD5;
    LI.SubItems.Add(aSFLFileRec.FilesName);
    LI.SubItems.Add(aSFLFileRec.FileMD5);
  end;
end;
Исправил:
Код:
procedure TSFLList.AddRecordToLV(aSFLFileRec: TSFLFile);
var
  LI: TListItem;
begin
Add(aSFLFileRec);
with fListView do
  begin
    LI := Items.Add;
    LI.Checked := aSFLFileRec.SearchByMD5;
    LI.SubItems.Add(aSFLFileRec.FilesName);
    LI.SubItems.Add(aSFLFileRec.FileMD5);
  end;
end;
Проблему не решило. Может быть стёк кто-то и забил но TobjectList.Count показывает что в списке 1 обьект.

А как можно посмотеть содержимое созданного мною класса в run-time?
Человек_Борща вне форума Ответить с цитированием
Старый 22.08.2011, 12:15   #9
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Меняпосетило просвящение. Программа убегала в бесконечный цикл.

свойство Records[i] читает данные из GetFile(i) а в GetFile вызвается Records. И стёк вешается.

Код:
    function GetFile(Indx: Integer): TSFLFile;
  public
    constructor Create;
    destructor Destroy; override;
    property Records[Indx: Integer]: TSFLFile read GetFile;

{...}

function TSFLList.GetFile(Indx: Integer): TSFLFile;
begin
  Result := Records[Indx];
end;
В GetFile нужно было вызывать GetItem(ну или Items унаследованное от Tlist) от TObjectList, чтобы тот вернул обьект.

По этому решение такое:
Код:
function TSFLList.GetFile(Indx: Integer): TSFLFile;
begin
  Result := (Items[Indx] as TSFLFile);
end;
Правильно ли так возвращать нужный результат?

Последний раз редактировалось Человек_Борща; 22.08.2011 в 12:20.
Человек_Борща вне форума Ответить с цитированием
Старый 22.08.2011, 12:19   #10
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

TSFLFile(GetItem(Index))
или
GetItem(Index) AS TSFLFile
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Организация исключения типа Estackoverflow Человек Панда Помощь студентам 3 07.07.2011 16:25
ошибка в классе Progsenya C# (си шарп) 6 02.04.2011 18:43
Ошибка в классе С++ evoz23 Помощь студентам 3 21.09.2010 10:56
Ошибка при заполнении БД: EStackOverFlow insense БД в Delphi 7 29.06.2010 14:38