Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2010.01.10;
Скачать: [xml.tar.bz2];

Вниз

Строку в объект   Найти похожие ветки 

 
kyn66 ©   (2009-11-12 16:11) [0]

Подскажите, каким способом можно строку вставить в объект , ну например ComboBox ? Нужно к примеру просканировать текущий каталог диска, найденные файлы записать в Combobox, а полный путь к файлу сохранить в объекте. Помню со строками есть проблемы при сохранении в объект. Есть вот такой вариант

....
var
 PS: PString;
...
procedure TForm1.FormCreate(Sender: TObject);
begin
 new(PS);
 PS^ := "Hello world 1";
 ComboBox1.Items.AddObject("Item1", TObject(PS));
 PS^ := "Hello world 2";
 ComboBox1.Items.AddObject("Item2", TObject(PS));
 PS^ := "Hello world 3";
 ComboBox1.Items.AddObject("Item3", TObject(PS));
...

procedure TForm1.FormDestroy(Sender: TObject);
begin
 Dispose(PS);
end;


При доступе к объекту

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
 ShowMessage(PString(Combobox1.Items.Objects[0])^); //Hello world 1
end;


возникает ошибка (AV)


 
Dennis I. Komarov ©   (2009-11-12 16:20) [1]

Даже и не знаю, чего тут поделать можно...

срочно "на дерево"...


 
kyn66 ©   (2009-11-12 16:22) [2]

Насчет AV разобрался(в ComboBox.Strings изначально были строки). Однако при извлечении строки - данные неверные, точнее <"Hello world 3"/B> везде присутствует. Вот так извлекаю

 ShowMessage(PString(Combobox1.Items.Objects[Combobox1.ItemIndex])^);


 
Юрий Зотов ©   (2009-11-12 16:54) [3]

Уберите указатели, работайте напрямую со строками и пишите их прямо в Combobox.Items (через Add, а не через AddObject)


 
kyn66 ©   (2009-11-12 17:07) [4]

Мне не Items составляет проблему. Туда строку и так запишу. Получается , что в ComboBox нужно две строки внести, типа

ComboBox1.AddObjects("Строка 1", Pointer(kodstr))


Только вместо Pointer(kodstr) нужно записать строку. Эта запись будет верна, если бы kodstr = Integer/ Мне же строка нужна.


 
kyn66 ©   (2009-11-12 17:10) [5]

Это нужно к тому, чтобы каждый Items ComboBox-а содержал в себе двойную информацию(две строки). Как вариант параллельно заводил переменную TStringList и в нее вносил вторые интересуемые строки, а потом сопостовлял их по ItemIndex. Но ведь это не есть лучший вариант?


 
LDV   (2009-11-12 17:14) [6]

Вот так:


procedure TForm1.Button2Click(Sender: TObject);
begin

 ComboBox1.Items.AddObject("Строка 1", TObject(Application.ExeName));

 ShowMessage(string(ComboBox1.Items.Objects[0]));

end;


 
Юрий Зотов ©   (2009-11-12 17:17) [7]

> kyn66 ©   (12.11.09 17:10) [5]

В смысле безопасности кода - возможно, лучший.

Без обид - Вы недостаточно знакомы с реализацией длинных строк в Delphi, поэтому и налетаете на ошибки работы с памятью.


 
RWolf ©   (2009-11-12 17:28) [8]

Чтоб не ходить по граблям:
type
 TMyContainer=class
    s:string;
    ...
 end;

...
container := TMyContainer.Create;
container.s := "this is a string";
ComboBox1.Items.AddObject("Item3", container);

...

ShowMessage(TMyContainer(Combobox1.Items.Objects[0]).s);

надо только не забыть перед очисткой комбобокса поудалять привязанные к нему объекты .


 
kyn66 ©   (2009-11-12 17:53) [9]


> RWolf ©   (12.11.09 17:28) [8]


Очень даже интересный вариант. Помнится кто то уже предлагал такой. Это код при условии если вводим один Item. А если их много? Как в данном случае container.s будет принимать значения и передавать их ComboBox ? Как обращаться к нему для получения конкретного значения по ItemIndex ?


 
Игорь Шевченко ©   (2009-11-12 17:54) [10]

у тебя столько вопросов, может, тебе проще программиста найти ?


 
kyn66 ©   (2009-11-12 17:55) [11]


Юрий Зотов ©   (12.11.09 17:17) [7]
> Без обид - Вы недостаточно знакомы с реализацией длинных
> строк в Delphi, поэтому и налетаете на ошибки работы с памятью.
>


Даже и близко нету. Поэтому и советуюсь с мастерами.


 
Dennis I. Komarov ©   (2009-11-12 17:55) [12]


> kyn66 ©   (12.11.09 17:53) [9]

array?


 
kyn66 ©   (2009-11-12 17:57) [13]


> Игорь Шевченко ©   (12.11.09 17:54) [10]
> у тебя столько вопросов, может, тебе проще программиста
> найти ?


Трудно отвечать? Вопросы возникают по мере необходимости реализации ситуации. Хочу знать больше. Это плохо? или я не в ту ветку постучался?


 
Игорь Шевченко ©   (2009-11-12 18:03) [14]


> Хочу знать больше.


Любите книгу - источник знаний


 
zlo   (2009-11-12 18:09) [15]


> А если их много? Как в данном случае container.s будет принимать
> значения и передавать их ComboBox ? Как обращаться к нему
> для получения конкретного значения по ItemIndex ?



type
 TStr = class
 private
   FStr: string;
   procedure SetStr(const Value: string);

 public
   constructor Create(AStr: string);

 property Str: string read FStr write SetStr;
 end;



{ TStr }

constructor TStr.Create(AStr: string);
begin
 Str := AStr;
end;

procedure TStr.SetStr(const Value: string);
begin
 if FStr <> Value then FStr := Value;
end;



{ TForm1 }

procedure TForm1.Button2Click(Sender: TObject);
begin
 ComboBox1.Items.AddObject("Item 1", TStr.Create("ObjectItem 1"));
 ComboBox1.Items.AddObject("Item 2", TStr.Create("ObjectItem 2"));
 ComboBox1.Items.AddObject("Item 3", TStr.Create("ObjectItem 3"));

 ShowMessage(TStr(ComboBox1.Items.Objects[0]).Str);
 ShowMessage(TStr(ComboBox1.Items.Objects[1]).Str);
 ShowMessage(TStr(ComboBox1.Items.Objects[2]).Str);
end;


 
Дмитрий Белькевич   (2009-11-12 18:21) [16]

Глобально:

1. Забыть (в большинстве случаев) New/Dispose.
2. Забыть (в большинстве случаев, кроме работы с сишными строками) при работе со строками/символами про указатели и нуль-терминированные строки.
3. Переписать с учетом забытого.


 
Leonid Troyanovsky ©   (2009-11-12 18:36) [17]


> kyn66 ©   (12.11.09 17:10) [5]

> Это нужно к тому, чтобы каждый Items ComboBox-а содержал
> в себе двойную информацию(две строки).

Такое делают, используя стили cbOwnerDraw*.
Item составляют из двух строк, разделенных неким разделителем,
например "|" or tab, а рисуют лишь одну из половин.

Но, в случае с файлами нет нужды хранить все в одном.
Проще хранить в одном комбобоксе имя устройства, во
втором - имена папок на нем, а в третьем ее содержимое.

Ну, и CB_DIR тебе в руки.

--
Regards, LVT.


 
Amoeba ©   (2009-11-12 22:30) [18]


> kyn66 ©   (12.11.09 16:11)
>
> Подскажите, каким способом можно строку вставить в объект
>

лучше промолчу, иначе гарантированное пожизненное  RO получу.


 
Leonid Troyanovsky ©   (2009-11-12 22:49) [19]


> Amoeba ©   (12.11.09 22:30) [18]

> лучше промолчу

Господа офицеры!
Как договорились - ни слова о ..

--
Regards, LVT.


 
kyn66 ©   (2009-11-12 23:02) [20]


> zlo   (12.11.09 18:09) [15]


Я думаю это то что нужно.


> Leonid Troyanovsky ©   (12.11.09 18:36) [17]


Да не о визуальном представлении идет речь, а о хранении данных(Имя файла - Items; Полный путь - Объект).


 
Leonid Troyanovsky ©   (2009-11-12 23:11) [21]


> kyn66 ©   (12.11.09 23:02) [20]

> Да не о визуальном представлении идет речь,

Когда говорят о комбобоксе, то о визуальном
представлении и речь.

Все остальное лишь кажется.

--
Regards, LVT.


 
kyn66 ©   (2009-11-12 23:13) [22]


> zlo   (12.11.09 18:09) [15]


Здается мне здесь еще нужно предусмотреть освобождение памяти после использования объектов.


 
kyn66 ©   (2009-11-12 23:28) [23]


> Leonid Troyanovsky ©   (12.11.09 23:11) [21]


А применение к нему AddObject как Сергей говорит каран запрещает? :)


 
Германн ©   (2009-11-13 01:42) [24]


> А применение к нему AddObject как Сергей говорит каран запрещает?
>  :)

Во-первых Сергей говорит кОран. А во-вторых что ты так зациклился на AddObject, что другие варианты не признаёшь?

Ну и плюс

> Юрий Зотов ©   (12.11.09 17:17) [7]
>
> > kyn66 ©   (12.11.09 17:10) [5]
>
> Без обид - Вы недостаточно знакомы с реализацией длинных
> строк в Delphi, поэтому и налетаете на ошибки работы с памятью.


 
{RASkov} ©   (2009-11-13 07:58) [25]

> [20] kyn66 ©   (12.11.09 23:02)
> Да не о визуальном представлении идет речь, а о хранении
> данных(Имя файла - Items; Полный путь - Объект).

Ну так и выбери другой контейнер для хранения двух строк.
Зачем мазахизмом заниматься?
type
 TDualStr = record
  NameFile, PathFile: String;
 end;
 TDualStrs: array of TDualStr;
Если нужно отоброжать то любой контрол с виртуальным режимом...


 
Юрий Зотов ©   (2009-11-13 08:38) [26]

> kyn66 ©   (12.11.09 23:28) [23]

Теперь прикиньте: Вы все же упорно хотите для хранения второй строки использовать свойство Objects и ради этого готовы "обернуть" эту вторую строку в специальный объект, за которым Вам еще придется "следить" - то есть вовремя создавать и уничтожать. Это дополнительный расход памяти, дополнительный код и дополнительный риск ошибок в этом коде.

А зачем? Разве не проще и не безопаснее (в смысле ошибок) делать именно так, как Вы вначале и делали - хранить вторые строки в отдельном списке и сопоставлять их по индексу?

Кроме того: если Вы собираетесь хранить списки файлов и каталогов, то, возможно, Вам подойдут готовые компоненты TDirectoryListBox и TFileListBox. Тогда, возможно, ничего программировать и не нужно будет.


 
kyn66 ©   (2009-11-13 09:12) [27]


> Юрий Зотов ©   (13.11.09 08:38) [26]



> А зачем? Разве не проще и не безопаснее (в смысле ошибок)
> делать именно так, как Вы вначале и делали - хранить вторые
> строки в отдельном списке и сопоставлять их по индексу?


Этот вариант был придуман давно. Просто я не думал что он совсем грамотный и "современный". А раз Мастер его утверждает, то на нем и останусь.


> А во-вторых что ты так зациклился на AddObject, что другие
> варианты не признаёшь?


Да нет, просто хотелось его иметь в своей копилке вариантов применения в определенных ситуациях. Когда нас учили в институте, то говорили, что инженер не обязан все держать в голове. Он должен знать и быстро определить где сможет получить ответ на тот или иной вопрос. Вот для этого копилка наработок и присутствует.


 
Dennis I. Komarov ©   (2009-11-13 09:48) [28]


> Он должен знать и быстро определить где сможет получить
> ответ на тот или иной вопрос.

delphimaster.ru :)


 
kyn66 ©   (2009-11-13 09:48) [29]


> Юрий Зотов ©   (13.11.09 08:38) [26]


Вот она, задумка - http://delphi.about.com/od/vclusing/a/items_addobject.htm
store one more additional string along the one displayed to the user.


 
kyn66 ©   (2009-11-13 09:49) [30]


> Dennis I. Komarov ©   (13.11.09 09:48) [28]
>
> delphimaster.ru :)


В том числе... ;)


 
Dennis I. Komarov ©   (2009-11-13 10:05) [31]


> kyn66 ©   (13.11.09 09:49) [30]

Ты не познал сути учения...


 
kyn66 ©   (2009-11-13 10:09) [32]


> Dennis I. Komarov ©   (13.11.09 10:05) [31]
> > kyn66 ©   (13.11.09 09:49) [30] Ты не познал сути учения.
> ..


Это как понять?


 
Dennis I. Komarov ©   (2009-11-13 10:53) [33]

Так и понимай, то что до тебя хотели донести этой фразой ты не осознал...


 
kyn66 ©   (2009-11-13 11:08) [34]


> Dennis I. Komarov ©   (13.11.09 10:53) [33]
> Так и понимай, то что до тебя хотели донести этой фразой
> ты не осознал...


Какой этой фразой ? Что вы все загадками говорите? Или нормально сказать гонор не позволяет?

В конечном итоге решение найдено. Цель достигнута после [15], спасибо автору за наводку + прочитка материала http://delphi.about.com/od/vclusing/a/items_addobject.htm . Тему можно закрыть . Всем спасибо!


 
Dennis I. Komarov ©   (2009-11-13 11:28) [35]


> Какой этой фразой ?

[28]

> Что вы все загадками говорите?

Ну не все же разжевывать...


 
kyn66 ©   (2009-11-13 11:35) [36]


> Ну не все же разжевывать...


Если по поводу частых обращений на  delphimaster.ru, то  уже сто раз говорил, что нато это и форум, чтобы здесь задавать вопросы и если кто считает нужным - на них отвечать. А не писать глупые ухмылочные намеки! Тем более ветка выбрана не для вундеркиндов. (Не все знаете учились на программистов... Некоторые учились этому через книги, вопросы, форумы и т.д.). Т.ч. коллеги, давайте не будем умничать, а отвечать по существу, если есть желание !!!


 
Григорьев Антон ©   (2009-11-13 12:57) [37]


> kyn66 ©   (13.11.09 11:35) [36]
> (Не все знаете учились на программистов... Некоторые учились
> этому через книги, вопросы, форумы и т.д.

Я вот тоже не учился на программиста :) Поэтому давайте с самого начала и вместе :)

Ваши строки искажаются потому, что string - это управлемый тип, т.е. компилятор следит за тем, сколько ссылок есть на строку, и при уничтожении всех ссылок освобождает память, выделенную под строку. Но интеллекта компилятора хватает только на то, чтобы отслеживать ссылки, явно объявленные как string. Когда вы приводите строку к TObject, вы получаете ещё одну фактическую ссылку на эту строку, но так она не имеет тип string, то компилятор игнорирует её при подсчёте. Теперь, как только все остальные ссылки будут освобождены, память, выделенная для строки, будет помечена как неиспользуемая, и в любой момент она может быть распределена для других нужд. А ссылка на эту память у вас осталась. В результате, когда вы обращаетесь по ней, то получаете более-менее случайный мусор.

Чтоюы этого не происходило, надо не приводить управляемые ссылки к левым типам. Одно из решений вам подсказали: использование классов. Классы - типы неуправляемые, никто ссылки на них не считает, сами никогда не удалятся, так что левые ссылки на них хранить достаточно безопасно. А уж в класс можно засунуть явно объявленную string, и компилятор правильно её посчитает. Но это - лишний расход ресурсов, как вам уже сказали.

Чтобы этого избежать, можно записывать в Objects ссылку на неуправляемую строку, т.е. на PChar. Только надо не забываь перед этим выделять для такой строки память (с помощью, например, StrNew), а потом, когда строка станет ненужной, удалять. Если вы не удалите такую ссылку вручную, то получите утечку памяти. Так что этот вариант требует некоторой внимательности. Как, впрочем, и вариант с использованием дополнительного TStringList: там тоже надо следить, чтобы списки были синхронизированы.


 
kyn66 ©   (2009-11-13 13:14) [38]


> Григорьев Антон ©   (13.11.09 12:57) [37]


Спасибо Антон за ликбез. Приятно читать умные слова. Из всего здесь выше сказанного я принял для себя  2 варианта. 1) Параллельное хранение данных в TStringList ; 2) Использование классов (очень понравился вариант). В нем я могу хранить много разных данных. Главное не забывать удалять ссылки на объекты. Вот такой вариан применил себе. Испробовано на 2-х типах данных. ВОт тестовый пример. Ничего лишнего и все работает на ура!

...
type
 TStr = class
   private
     FName : string;
     FOlds : Integer;
   public
     property Name: String read FName;
     property Olds: Integer read FOlds;
     constructor Create(Const name: string; Const olds : Integer);
 end;
...
 procedure FreeObjects(const strings: TStrings) ;
implementation

{$R *.dfm}

constructor TStr.Create(Const name: string; Const olds : Integer);
begin
 FName := name;
 FOlds := olds;
end;

procedure TForm1.FreeObjects(const strings: TStrings) ;
var
 idx : integer;
begin
 for idx := 0 to Pred(strings.Count) do
 begin
   strings.Objects[idx].Free;
   strings.Objects[idx] := nil;
 end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 FreeObjects(ComboBox1.Items);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 ComboBox1.Items.AddObject("Item 1", TStr.Create("ObjectItem 1", 1));
 ComboBox1.Items.AddObject("Item 2", TStr.Create("ObjectItem 2", 2));
 ComboBox1.Items.AddObject("Item 3", TStr.Create("ObjectItem 3", 3));
end;

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
 ShowMessage(TStr(ComboBox1.Items.Objects[ComboBox1.ItemIndex]).Name + #10#13 +
             IntToStr(TStr(ComboBox1.Items.Objects[ComboBox1.ItemIndex]).Olds));
end;
....

А вот по поводу PChar, то вроде в [0] все с этого и начиналось.

> Ваши строки искажаются потому, что string - это управлемый
> тип, т.е.

Не совсем искажаются, а при кликах по любому Items выдает одно и то же значение "объекта"

Да и сообщение [16] как то насторожило и заставило подумать почему так?

В конечном итоге можно было остановиться на использовании TStringList с синхронизацией.... Но хочется изучить и применить нечто новое. Интересовали новые, другие доступные механизмы.


 
SergP ©   (2009-11-13 13:25) [39]


> Подскажите, каким способом можно строку вставить в объект
> , ну например ComboBox ? Нужно к примеру просканировать
> текущий каталог диска, найденные файлы записать в Combobox,
>  а полный путь к файлу сохранить в объекте. Помню со строками
> есть проблемы при сохранении в объект.


А зачем все это?
Если рассуждать в пределах данного примера, то:
полный путь к файлу = путь к каталогу +"\" +имя файла
А если ты сканируешь определенный каталог, то значит путь к этому каталогу  для всех файлов одинаковый...

Или у тебя просто пример неудачный?


 
kyn66 ©   (2009-11-13 13:32) [40]


> SergP ©   (13.11.09 13:25) [39]
>
>Или у тебя просто пример неудачный?


ТОбою не понята суть вопроса. Вопрос был из области AddObject с передачей строки в качестве параметра. Он впринципе уже решен. Почитай ветку полностью, могет пригодится ;)


 
Григорьев Антон ©   (2009-11-13 13:38) [41]


> Использование классов (очень понравился вариант). В нем
> я могу хранить много разных данных.

А параллельно с этим хранится ещё куча данных, унаследованных от TObject, а также служебной информации. Если хотите "много и просто", используйте лучше record. Если памятью для них управлять с помощью New и Dispose, никаких проблем с управляемыми типами внутри не возникает.

> А вот по поводу PChar, то вроде в [0] все с этого и начиналось.

Там не PChar был, а PString. И в одну и ту же строку вы записывали разные значения. А AddObject просто сохраняет указатель, он не делает копию того, что вы передаёте. В результате вы каждый раз перезаписывали строку, уже добавленную в Objects.


 
Игорь Шевченко ©   (2009-11-13 13:42) [42]


> Если по поводу частых обращений на  delphimaster.ru, то
>  уже сто раз говорил, что нато это и форум, чтобы здесь
> задавать вопросы и если кто считает нужным - на них отвечать.
>  А не писать глупые ухмылочные намеки! Тем более ветка выбрана
> не для вундеркиндов. (Не все знаете учились на программистов.
> .. Некоторые учились этому через книги, вопросы, форумы
> и т.д.). Т.ч. коллеги, давайте не будем умничать, а отвечать
> по существу, если есть желание !!!


http://ln.com.ua/~openxs/articles/smart-questions-ru.html

читать до полного просветления.


 
kyn66 ©   (2009-11-13 13:52) [43]


> А AddObject просто сохраняет указатель, он не делает копию
> того, что вы передаёте. В результате вы каждый раз перезаписывали
> строку, уже добавленную в Objects.


Согласен. Я уже и сам до этого додумался, посмотрев внимательно.

>  Если памятью для них управлять с помощью New и Dispose,
>  никаких проблем с управляемыми типами внутри не возникает.


Вот эта строка не совсем понятна. Речь идет о записях впринципе или о их содержимом?


 
Leonid Troyanovsky ©   (2009-11-13 14:18) [44]


> kyn66 ©   (13.11.09 13:52) [43]

> >  никаких проблем с управляемыми типами внутри не возникает.

> Вот эта строка не совсем понятна. Речь идет о записях впринципе
> или о их содержимом?

RTFM: Finalize procedure.

--
Regards, LVT.


 
Ухарь   (2009-11-13 14:19) [45]


> kyn66 ©   (13.11.09 13:52) [43]
>
>



> Речь идет о записях впринципе или о их содержимом?


Речь идет о том, что если использовать  New и Dispose, то мы будем иметь дело каждый раз с разной структурой (или строкой, или объектом - не важно, в общем - с разными областями памяти), и на каждом проходе получать новый указатель.
А не добавлять один и тот же адрес во все элементы списка.
В случае использования объекта и его конструктора ровным счетом то же самое и происходит, если такой подход по каким то причинам не устраивает, нужно сделать тоже самое, но руками


 
Григорьев Антон ©   (2009-11-13 14:30) [46]


> Вот эта строка не совсем понятна. Речь идет о записях впринципе
> или о их содержимом?

О содержимом. Если память под запись выделять и освобождать через GetMem/FreeMem, то освобождаться будет только память, выделенная под саму структуру, а содержищиеся в ней управляемые типы данных должным образом освобождены не будут. А если использовать New/Dispose, то будут, нато только при вызове Dispose не забывать приводить указатель к правильному типу. А вот если в записи есть неуправляемые ссылки на внешние данные (типа того же PChar), то тут уже в любом случае руками освобождать надо.


 
kyn66 ©   (2009-11-13 15:03) [47]

Вот этот пример http://k210.org/delphi/components/49/ можно отнести к классу правильного использования записей для хранения строковых данных?


 
Григорьев Антон ©   (2009-11-13 15:18) [48]


> kyn66 ©   (13.11.09 15:03) [47]

Вроде никаких ошибок я там не вижу.


 
kyn66 ©   (2009-11-13 15:51) [49]


> Григорьев Антон ©   (13.11.09 15:18) [48]
> Вроде никаких ошибок я там не вижу.
</I

Т.е. здесь и память правильно выделяется new(MyRec);, затем полю записи присваевается значение для "хранения" MyRec^.path:=OpenDialog1.FileName; и затем все грамотно высвобождается for i:=0 to ListView1.Items.Count-1 do
   Dispose(PMyRec(ListView1.Items[i].Data));
Здесь применительно к TListView. Значит если я хочу применить это к своему варианту с ComboBox(для него я думаю такая технология тоже подойдет) нужно сделать так(по типу [38])?


procedure TForm1.FormCreate(Sender: TObject);
begin
  new(MyRec);
   MyRec^.path:="FromObjectItem 1";
   ComboBox1.Items.AddObject("Item 1", Pointer(MyRec));
  new(MyRec);
   MyRec^.path:="FromObjectItem 2";
   ComboBox1.Items.AddObject("Item 2", Pointer(MyRec));
  new(MyRec);
   MyRec^.path:="FromObjectItem 3";
   ComboBox1.Items.AddObject("Item 3", Pointer(MyRec));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 FreeObjects(ComboBox1.Items);// описана в [38]
end;


 
kyn66 ©   (2009-11-13 16:10) [50]

Проверил - все работает. Однако ошибка AV FreeObjects(ComboBox1.Items);// описана в [38]. Объекты не правильно удаляю.
Скорее всего вот так правильно?

 for i := 0 to ComboBox1.Items.Count - 1 do
  Dispose(PMyRec(ComboBox1.Items.Objects[i]));


 
Leonid Troyanovsky ©   (2009-11-13 17:39) [51]


> kyn66 ©   (13.11.09 16:10) [50]

> Проверил - все работает. Однако ошибка AV FreeObjects(ComboBox1.
> Items);// описана в [38].

Помылся б ты, ёжик.

--
Regards, LVT.


 
kyn66 ©   (2009-11-13 17:52) [52]


> Leonid Troyanovsky ©   (13.11.09 17:39) [51]


УмнО от мастера такое слышать. Не у одного меня такие проблемы, млин...

http://www.cyberforum.ru/delphi-beginners/thread49246.html


 
zlo   (2009-11-13 18:16) [53]


type
 PNameOldsRec = ^TNameOldsRec;
 TNameOldsRec = record
   Name: string;
   Olds: Integer;
 end;

function CombineNameAndOlds(AName: string; AOlds: Integer): TObject;
var
 P: PNameOldsRec;
begin
 New(PNameOldsRec(Result));
 with PNameOldsRec(Result)^ do
 begin
   Name := AName;
   Olds := AOlds;
 end;
end;

procedure TForm2.Button1Click(Sender: TObject);
var
 I: Integer;
begin
 ComboBox1.Items.AddObject("", CombineNameAndOlds("Строка 1", 1));
 ComboBox1.Items.AddObject("", CombineNameAndOlds("Строка 2", 2));

 for I := 0 to ComboBox1.Items.Count - 1 do
   with PNameOldsRec(ComboBox1.Items.Objects[I])^ do
     ShowMessageFmt("Name: %s; Olds: %d", [Name, Olds]);

 for I := 0 to ComboBox1.Items.Count - 1 do
   Dispose(PNameOldsRec(ComboBox1.Items.Objects[I]));
end;


 
zlo   (2009-11-13 18:18) [54]

забыл убрать var P: PNameOldsRec; из CombineNameAndOlds


 
kyn66 ©   (2009-11-13 20:06) [55]


> zlo   (13.11.09 18:16) [53]


Спасибо тебе, добрый человек! Это похоже на мои мысли [49] + [50], только оформлено более аккуратнее. Отлично. Сейчас проверю в деле...

ЗЫ:
Ник совсем не подходит ;).


 
kyn66 ©   (2009-11-13 20:41) [56]

Я думаю [53] следуе добавить очистку ComboBox после уничтожения объектов.

  for I := 0 to ComboBox1.Items.Count - 1 do
    Dispose(PNameOldsRec(ComboBox1.Items.Objects[I]));
  ComboBox1.Clear;


В противном случае

with PNameOldsRec(ComboBox1.Items.Objects[I])^ do
    ShowMessageFmt("Name: %s; Olds: %d", [Name, Olds]);

всеравно выполняется, но с мусором. Проверял разделив этот кусок кода  procedure TForm2.Button1Click на три раздельных для последовательности действий.

procedure TForm1.Button2Click(Sender: TObject);
begin
ComboBox2.Items.AddObject("Первая строка Комбо", CombineNameAndOlds("Строка 1", 1));
ComboBox2.Items.AddObject("Вторая строка Комбо", CombineNameAndOlds("Строка 2", 2));
end;

procedure TForm1.ComboBox2Change(Sender: TObject);
begin
 with PNameOldsRec(ComboBox2.Items.Objects[ComboBox2.ItemIndex])^ do
  ShowMessageFmt("Name: %s; Olds: %d", [Name, Olds]);
end;

procedure TForm1.Button3Click(Sender: TObject);
Var
 i : Integer;
begin
 for I := 0 to ComboBox2.Items.Count - 1 do
  Dispose(PNameOldsRec(ComboBox2.Items.Objects[I]));
 ComboBox2.Clear;
end;

Да и пустая добавляемая строка сперва сбила с толку, почему комбо пустой получается... ComboBox1.Items.AddObject("", CombineNameAndOlds("Строка 1", 1));

А так все прэлесно... :)


 
Дмитрий Белькевич   (2009-11-13 23:20) [57]

Я бы всё таки к [17] сколнялся. Слишком всё сложно - объекты, создание/разрушение, указатели, разыменовывание, следить за всем этим добром... Нафига? [17] - это две-три строки кода, безо всяких излишест.

В ComboBox1DrawItem что-то типа TextOut(Rect.Left,Rect.Top, ExtractFileName(Items[Index]));

Для общего случая вместо ExtractFileName можно каку-то другую функцию сделать, выделяющую нужный для отображения кусок строки.


 
Leonid Troyanovsky ©   (2009-11-13 23:51) [58]


> kyn66 ©   (13.11.09 17:52) [52]

> УмнО от мастера такое слышать. Не у одного меня такие проблемы

Проблемы буратин нам понятны.
Для них папы карлы, можно сказать, последние курточки загоняют,
но буратины предпочитают букварю шоу одного актера.

New&Free - где ж твой букварь?

--
Regards, LVT.


 
kyn66 ©   (2009-11-14 18:06) [59]


> Leonid Troyanovsky ©   (13.11.09 23:51) [58]


Осталось правильно расставить

Begin

end;


 
kyn66 ©   (2009-11-14 20:02) [60]


> Дмитрий Белькевич   (13.11.09 23:20) [57]


Ну тут уже подумать нужно что проще. Если все делается на одной форме и работаем с объектами, то в нужном месте их инициализируем, получаем/присваиваем данные, при закрытии формы уничтожаем. Все. Если же работать с частями строк[17], то здесь тоже не обойдется без дополнительных функций по извлечению и показу нужной части строки, извлечению, преобразованию к нужным типам данных (если числовой) и т.д. Т.е. в любом варианте есть свои нюансы. А если известен механизм, то уже можно придумать куда и как лучше его применить. Кстати, проверил отработку [56] совместно с AllocMemSize - все отлично. Механизм работает, утечки памяти отсутствуют. Что и требовалось получить в конечном итоге.


 
Дмитрий Белькевич   (2009-11-15 01:31) [61]

> Все.

А в случае бех объектов даже инициализировать/уничтожать ничего не нужно :)

>то здесь тоже не обойдется без дополнительных функций по извлечению и показу нужной части строки

Функция - одна, принимающая разделитель и строку на вход и отдающая одну или две части. Пишется минут за 5.

>преобразованию к нужным типам данных (если числовой)

Так это и у тебя нужно. Как же ты собираешься сразу числовой тип отображать? :)

>Механизм работает, утечки памяти отсутствуют.

Ну так большая часть и отсюда: http://govnokod.ru/ вполне работает.


 
kyn66 ©   (2009-11-15 02:33) [62]


> Функция - одна, принимающая разделитель и строку на вход
> и отдающая одну или две части. Пишется минут за 5.


Я не сказал что это сложно. К тому же у RX есть хороший набор функций по работе со строками.


> Так это и у тебя нужно. Как же ты собираешься сразу числовой
> тип отображать? :)


Берем из объекта поле записи типа Integer и юзаем его :)


> Ну так большая часть и отсюда: http://govnokod.ru/ вполне
> работает.


:)


> А в случае бех объектов даже инициализировать/уничтожать
> ничего не нужно :)


Работа с простыми строками уже как бы известный механизм. Хотелость попробывать изучить работу объектов. Поправде говоря к указателям раньше ваще никогда не приходилось обращаться. А сейчас просто чисто из интереса. Хочется все же понять что это такое.


 
Германн ©   (2009-11-15 02:47) [63]


>
> Работа с простыми строками уже как бы известный механизм.
>  Хотелость попробывать изучить работу объектов. Поправде
> говоря к указателям раньше ваще никогда не приходилось обращаться.
>  А сейчас просто чисто из интереса.

Тогда читай книги (учебники).


 
имя   (2009-11-15 03:02) [64]

Удалено модератором


 
Юрий Зотов ©   (2009-11-15 10:34) [65]

> kyn66 ©   (15.11.09 02:33) [62]

> к указателям раньше ваще никогда не приходилось обращаться. А сейчас
> просто чисто из интереса. Хочется все же понять что это такое.

Дык... а что там понимать? Указатель - это переменная, содержащая адрес. Только и всего.

Кстати, длинные строки, динамические массивы, объекты - все это тоже указатели.


 
Дмитрий Белькевич   (2009-11-15 21:16) [66]


> Берем из объекта поле записи типа Integer и юзаем его :)


Если нужен и Integer (для последующего его применения) и строчка (для отображения) то строчка запихивается в комбобокс, integer - в указатель:

AddObject(s, Pointer(i))

>Поправде говоря к указателям раньше ваще никогда не приходилось обращаться. А сейчас просто чисто из интереса. Хочется все же понять что это такое.

Жаль только применение крайне неудачное.

Понять указатели? Ну можешь мои статьи посмотреть:

http://www.makhaon.com/articles/


 
kyn66 ©   (2009-11-15 21:59) [67]


> Юрий Зотов ©   (15.11.09 10:34) [65]
> .. а что там понимать? Указатель - это переменная, содержащая
> адрес. Только и всего.

Это сейчас я уже понял. Просто раньше небыло нужды в их изучении и ессно читать про это не хотелось. Сейчас заинтересовало.

>Кстати, длинные строки, динамические
> массивы, объекты - все это тоже указатели.

Да, но за их уничтожение отвечает Delphi.

Я вот тут статейку почтал интересную http://www.citforum.ru/programming/bp70_ug/bp70ug_08.shtml . Так вот там есть подраздел "Потери динамически распределяемой памяти" Так вот там не совсем понятен один момент

Общей причиной утечек памяти является переприсваивание динамических переменных без освобождения  предыдущих. Простейшим случаем является следующий:
   var IntPointer: ^Integer;
      begin
         New(IntPointer);
         New(IntPointer);
      end.


Это похоже на ситуацию как у меня в тестовом примере, где я инициализирую указатель под одним и тем же именем в цикле с последующими некоторыми действиями с ним.

type
  PMyRecord = ^TMyRecord;
  TMyRecord = record
    id: Integer;
    Name: string;
  end;
....
procedure TForm1.Button3Click(Sender: TObject);
var
 i: Integer;
 pRec: PMyRecord;
begin
 for i := 0 to 10 do
  begin
    new(pRec);
    pRec^.id := i;
    pRec^.Name := "Entry" + IntToStr(i);
    ListView1.AddItem("Entry" + IntToStr(i), Pointer(pRec));
  end;
end;


Не будет ли это нарушением? Точнее не спровацирetn kb это утечку? Хотя опять же проверял перед инициализацией и после удаления через  ShowMessage(IntToStr(AllocMemSize)); Все вроде нормально...


 
kyn66 ©   (2009-11-15 22:15) [68]


> Жаль только применение крайне неудачное.

Это частный случай, просто нужно было что-то привести в качестве примера, чтобы поняли что нужно.


> Понять указатели? Ну можешь мои статьи посмотреть:

Спасибо, посмотрю. Кстати, по поводу разыминования.... Только чур ногами не бить, чисто эксперимент. Если из вышеприведенного кода [67] в момент присваивания значений

new(pRec);
   pRec^.id := i;
   pRec^.Name := "Entry" + IntToStr(i);


Сперва я присвоил как в коде, потом убрал знак ^ и опять выполнил присваивание. Хотя понимаю, что pRec^.id - конкретно переменная, а pRec.id указатель на адрес в памяти, где эта меременная находится. После проверки обеих вариантов через

procedure TForm1.ListView1Click(Sender: TObject);
var
 i: Integer;
 xRec: PMyRecord;
begin
 for i := 0 to Listview1.Items.Count - 1 do
  if ListView1.Items[i].Selected then
   begin
     xRec := PMyRecord(ListView1.Items[i].Data);
     ShowMessage(Format("Record #%d Name: %s", [xRec.id, xRec.Name]));
   end;
end;


Значения были одинаковые. Совпадение?

PS
Касаемо литературы и прочих источников информации. Delphi World у меня как настольная книга, которая всегда под руками. Хочу сказать, что там не без ошибок коды приведены. А в книгах? Не может быть очепятки? Вот форум и помогает соединить все вопросы и дать правильный ответ.


 
Юрий Зотов ©   (2009-11-15 22:17) [69]

> kyn66 ©   (15.11.09 21:59) [67]

За освобождение объектов Delphi не отвечает, это должен делать программист. Правда, есть еще такая штука, как интерфейсы, там все хитрее - видимо, Вам теперь стоит разобраться и с ними, чтобы эту тему закрыть.

Что касается примеров кода, то между ними есть большая разница.

var
 IntPointer: ^Integer;
begin
  New(IntPointer);
  New(IntPointer);
end.

Здесь память выделяется дважды, но после второго New адрес первого выделенного блока будет безвозвратно потерян (затерт вторым адресом, потому что второй адрес пишется в ту же переменную, которая до этого хранила первый адрес). Теперь первому блоку нельзя сделать Dispose (нечего передать в параметре) - чистейшая утечка памяти.

procedure TForm1.Button3Click(Sender: TObject);
var
 i: Integer;
 pRec: PMyRecord;
begin
 for i := 0 to 10 do
 begin
    new(pRec);
    pRec^.id := i;
    pRec^.Name := "Entry" + IntToStr(i);
    ListView1.AddItem("Entry" + IntToStr(i), Pointer(pRec));
 end;
end;

Здесь для выделения 11 блоков памяти тоже использована одна переменная, которая, конечно, каждый раз затирается новым адресом. Но старый адрес при этом не теряется, потому что его копия запоминается в Items[i].Data и мы можем вызвать Dispose, используя эту копию.


 
Юрий Зотов ©   (2009-11-15 22:23) [70]

> kyn66 ©   (15.11.09 22:15) [68]

> pRec^.id - конкретно переменная,
> а pRec.id указатель на адрес в памяти

Обе формы записи равнозначны. Delphi автоматически разыменовывает указатели, поэтому значок ^ при разыменовании можно не писать. Но это не всегда хорошо (снижается читабельность кода), поэтому многие (и я в том числе) используют такое правило - разыменовывать указатели на объекты (то есть, переменные любого объектного типа) поручают компилятору, а остальные указатели разыменовывают явно, указывая значок ^.


 
kyn66 ©   (2009-11-15 22:56) [71]


> но после второго New адрес первого выделенного блока будет
> безвозвратно потерян

Он будет потерян, но выделенным так и останется(утечка памяти!). А в моем случае переменная одна и та же, но после инициализации она сделала "доброе дело", присвоив этому адресу некие данные, а уж потом получила новый адрес. Получается все открытые дыры будут заделаны (данными). И тогда

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
 i:integer;
begin
 for i:=0 to ListView1.Items.Count-1 do
   Dispose(PMyRecord(ListView1.Items[i].Data));
end;

наилучшим способом очистит память... Я все правильно понял?

> Delphi автоматически разыменовывает указатели, поэтому значок
> ^ при разыменовании можно не писать.

Вот так вот....

> поэтому многие (и я в том числе) используют такое правило
> - разыменовывать указатели на объекты

Что считается в программировании  - правилом хорошего тона...


 
Юрий Зотов ©   (2009-11-16 00:16) [72]

> kyn66 ©   (15.11.09 22:56) [71]

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

Главное не это, а то, что перед тем, как переменная получила новое значение, ее старое значение было сохранено в Items[i].Datа. Поэтому адреса выделенных блоков не теряются и мы имеем возможность вызвать Dispose для всех блоков.

> Я все правильно понял?

Да, код верный.


 
Германн ©   (2009-11-16 02:25) [73]


> kyn66 ©

Везёт тебе! Постарайся не упустить это везение!


 
Leonid Troyanovsky ©   (2009-11-16 07:43) [74]


> Дмитрий Белькевич   (15.11.09 21:16) [66]

> Если нужен и Integer (для последующего его применения) и
> строчка (для отображения) то строчка запихивается в комбобокс,
>  integer - в указатель:

> AddObject(s, Pointer(i))

Integer не годится, бо stdctrls.pas

function TCustomComboBoxStrings.GetObject(Index: Integer): TObject;
begin
 Result := TObject(SendMessage(ComboBox.Handle, CB_GETITEMDATA, Index, 0));
 if Longint(Result) = CB_ERR then
   Error(SListIndexError, Index);
end;

-1 для классов LISTBOX & COMBOBOX - индикатор ошибки.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2009-11-16 07:59) [75]


> kyn66 ©   (15.11.09 02:33) [62]

>  Хотелость попробывать изучить работу объектов.

Был хороший повод изучить "виртуальные" контролы.

> там не без ошибок коды приведены. А в книгах? Не может быть
> очепятки? Вот форум и помогает соединить все вопросы и дать
> правильный ответ.

Обсуждения позволяют избавиться от заблуждений.
Желающим, конечно.

--
Regards, LVT.


 
Anatoly Podgoretsky ©   (2009-11-16 09:02) [76]

> Leonid Troyanovsky  (16.11.2009 07:59:15)  [75]

Одного желания мало.


 
Leonid Troyanovsky ©   (2009-11-16 09:13) [77]


> Anatoly Podgoretsky ©   (16.11.09 09:02) [76]

> Одного желания мало.

Да, конечно.
Если нет способности к восприятию информации,
в т.ч. из-за слабой подготовки, то вместо диалога
получаются несвязные монологи.

--
Regards, LVT.


 
kyn66 ©   (2009-11-16 09:24) [78]


> Главное не это, а то, что перед тем, как переменная получила
> новое значение, ее старое значение было сохранено в Items[i].
> Datа. Поэтому адреса выделенных блоков не теряются и мы
> имеем возможность вызвать Dispose для всех блоков.


Получается так, что если память выделена, то ее обязательно нужно чем-то заполнить. Если же проходя в цикле не выполнить ListView1.AddItem("Entry" + IntToStr(i), Pointer(pRec)); то и в этом случае получится незаполненная дыра. И не выскочит ли тогда ошибка при удалении объектов

for i:=0 to ListView1.Items.Count-1 do
  Dispose(PMyRecord(ListView1.Items[i].Data));
end;

если предварительно не проверить

  if PMyRecord(ListView1.Items[i].Data)) <> nil
   ...


 
RWolf ©   (2009-11-16 09:29) [79]


> Получается так, что если память выделена, то ее обязательно
> нужно чем-то заполнить

К выделенной памяти только одно требование — её обязательно
нужно когда-нибудь освободить. А уж заполнять или нет — это на усмотрение программиста.


 
sniknik ©   (2009-11-16 09:30) [80]

> Dispose(PMyRecord(ListView1.Items[i].Data));
PMyRecord(ListView1.Items[i].Data).Free;


 
Юрий Зотов ©   (2009-11-16 09:30) [81]

> kyn66 ©   (16.11.09 09:24) [78]

> Получается так, что если память выделена, то ее обязательно нужно
> чем-то заполнить.

Заполнять не обязательно. Обязательно другое - помнить адрес выделенного блока, чтобы потом можно было его освободить.

Похоже, Вы пока еще немного путаетесь. Есть АДРЕС выделенного блока, а есть СОДЕРЖИМОЕ этого блока. Это совершенно разные вещи. Адрес хранится в переменной типа "указатель", а содержимое хранится в самом блоке.


 
sniknik ©   (2009-11-16 09:33) [82]

а ну да, если у тебя там "дыры" то значит повторное использование тоже будет. значит
FreeAndNil(PMyRecord(ListView1.Items[i].Data));


 
Leonid Troyanovsky ©   (2009-11-16 09:47) [83]


> sniknik ©   (16.11.09 09:30) [80]

В начале было New.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2009-11-16 09:54) [84]


> kyn66 ©   (16.11.09 09:24) [78]

>   if PMyRecord(ListView1.Items[i].Data)) <> nil

Здесь приведение лишнее, бо загромождает суть.

--
Regards, LVT.


 
kyn66 ©   (2009-11-16 10:03) [85]


> Заполнять не обязательно. Обязательно другое - помнить адрес
> выделенного блока, чтобы потом можно было его освободить.
>


Но в данном случае (заполнение в цикле) переменная инициализируется, получает/не получает значение, инициализируется на новый блок памяти. И имя переменной, связанной с конкретным блоком мы как таковое теряем. Т.е. к конкретному блоку по имени мы обратиться не сможем. Поэтому мы в цикле пробегаем по всем итемам и удаляем, если что то там есть

for i:=0 to ListView1.Items.Count-1 do
 Dispose(PMyRecord(ListView1.Items[i].Data));
end;


> Есть АДРЕС выделенного блока, а есть СОДЕРЖИМОЕ этого блока.
>  Это совершенно разные вещи. Адрес хранится в переменной
> типа "указатель", а содержимое хранится в самом блоке.

Не, с этим похоже разобрался уже.


 
Leonid Troyanovsky ©   (2009-11-16 10:11) [86]


> kyn66 ©   (16.11.09 10:03) [85]

> блок памяти. И имя переменной, связанной с конкретным блоком
> мы как таковое теряем. Т.е. к конкретному блоку по имени
> мы обратиться не сможем. Поэтому мы в цикле пробегаем по
> всем итемам и удаляем, если что то там есть

У блока нет имени, а есть адрес, скажем, его начала,
который хранят в к.л. переменной (ну, и размер блока).
В какой переменной - это на усмотрение программиста.
Как это делать правильно тебе уже объясняли.

--
Regards, LVT.


 
kyn66 ©   (2009-11-16 10:26) [87]


> У блока нет имени, а есть адрес, скажем, его начала,

Пардонс, не так выразился. Конечно же адрес(имелось ввиду имя переменной для конкретнокго адреса блока памяти). Информации предостаточно. Большое спасибо всем мастерам за разъяснения и толерантность.


 
Демо ©   (2009-11-16 11:33) [88]


> for i:=0 to ListView1.Items.Count-1 do
>  Dispose(PMyRecord(ListView1.Items[i].Data));
> end;


Просто проверь - ссылается ли куда-то ListView1.Items[i].Data:

for i:=0 to ListView1.Items.Count-1 do
begin
  if ListView1.Items[i].Data<> nil then Dispose(PMyRecord(ListView1.Items[i].Data));
end;


 
sniknik ©   (2009-11-16 11:35) [89]

> В начале было New.
догадался... тема сбила "Строку в объект", как то больше в другим ассоциируется.


 
kyn66 ©   (2009-11-16 13:05) [90]


> Leonid Troyanovsky ©   (16.11.09 09:54) [84]
> if PMyRecord(ListView1.Items[i].Data)) <> nil
>Здесь приведение лишнее, бо загромождает суть.


Т.е. в данном случае важнее узнать есть ли там что либо для уничтожения и не важно какого типа?

if (ListView1.Items[i].Data) <> nil


 
kyn66 ©   (2009-11-16 13:09) [91]

Не дописал строку. Хотел сказать что в данном случае тогда и удаление можно выполнять без приведения? Какая разница что удалять?

if ListView1.Items[i].Data<> nil then
 Dispose(ListView1.Items[i].Data);


 
Leonid Troyanovsky ©   (2009-11-16 13:26) [92]


> kyn66 ©   (16.11.09 13:09) [91]

> и удаление можно выполнять без приведения?

А вот для удаления это важно, бо если компилятор не знает тип,
то он и не вставит Finalize для очистки, скажем, строк.

--
Regards, LVT.


 
kyn66 ©   (2009-11-16 13:58) [93]


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


Ага... решил мастера поймать... :) Дело в том, что я проверил еще одну ситуацию на коде из трех кнопок.
1) Запускает цикл с инициализацией переменной указателя, присваивает значения;
2) Удаление объектов:
3) Просто показывает память ShowMessage(IntToStr(AllocMemSize));

Так вот. Запускаю форму, проверяю память - 12252. Запускаю цикл и опять проверяю память - 14000, уничтожаю объекты с приведением - 12284. Хотя память не вернулась к числу начальному 12252(нужно разобраться почему). Однако, когда я делаю уничтожение без приведения, память - 12460. Тоже не возвращается к начальному 12252

procedure TForm1.Button2Click(Sender: TObject);
var
 i:integer;
begin
 for i:=0 to ListView1.Items.Count-1 do
   Dispose({PMyRecord}(ListView1.Items[i].Data));
 ListView1.Clear;
end;


 
Дмитрий Белькевич   (2009-11-16 14:57) [94]

>Хотя память не вернулась к числу начальному 12252(нужно разобраться почему)

Кроме твоих записей может (и будет) создаваться разный самоуничтожаемый "мусор".


> Однако, когда я делаю уничтожение без приведения, память
> - 12460. Тоже не возвращается к начальному 12252


Смотри сырцы - найдёшь много интересного:

procedure _Dispose(p: Pointer; typeInfo: Pointer);
begin
 _Finalize(p, typeinfo);
 FreeMem(p);
end;

typeinfo, я так думаю, отдаётся разный и финализация происходит неверно.

В дополнение к экспериментам рекомендую использовать FastMM. Она сразу же утечки покажет.


 
Дмитрий Белькевич   (2009-11-16 15:12) [95]

>Хотя память не вернулась к числу начальному 12252(нужно разобраться почему)

Опять же - фрагментацию памяти не стоит забывать. Фрагментация памяти, кстати, одна из причин, по которой я бы не рекомендовал использовать New/Dispose. Если уж очень хочется извращаться - делай динамический массив записей и единомоментно (или "чанками" по тысяче, если заранее неизвестен размер) устанавливай его размер. Это сильно уменьшит фрагментацию памяти и ускорит работу, иногда на порядок.


 
kyn66 ©   (2009-11-16 15:17) [96]


> typeinfo, я так думаю, отдаётся разный и финализация происходит
> неверно.

Да действительно, Leonid Troyanovsky ©   (16.11.09 13:26) [92] уже это подчеркнул.

> В дополнение к экспериментам рекомендую использовать FastMM.
>  Она сразу же утечки покажет.

Да, спасибо, сечас буду почитать про него.


 
Leonid Troyanovsky ©   (2009-11-16 15:36) [97]


> kyn66 ©   (16.11.09 13:58) [93]

> цикл и опять проверяю память - 14000, уничтожаю объекты
> с приведением - 12284. Хотя память не вернулась к числу
> начальному 12252(нужно разобраться почему).

Возможно, что, например, первый показ ShowMessage требует
память для регистрации класса.
Попробуй повторить создание-разрушение дважды
(без уничтожения формы).

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2009-11-16 15:38) [98]


> Leonid Troyanovsky ©   (16.11.09 15:36) [97]

> память для регистрации класса.

В смысле: для регистрации класса окна.

--
Regards, LVT.


 
Дмитрий Белькевич   (2009-11-16 15:39) [99]

Сразу же смотри FullDebugMode. Это дополнительно укажет двойное освобождение переменных.


 
Дмитрий Белькевич   (2009-11-16 15:41) [100]


> Попробуй повторить создание-разрушение дважды(без уничтожения
> формы).


А лучше без формы и, вообще, без VCL"а и без окон (в консольном приложении). VCL и Winapi много неявнях телодвижений с памятью делают.


 
kyn66 ©   (2009-11-16 15:57) [101]


> Leonid Troyanovsky ©   (16.11.09 15:36) [97]
>Попробуй повторить создание-разрушение дважды(без уничтожения >формы).

Без разницы. Как толькл открылась форма 12252. По пять раз создавал уничтожал - 12284. Однако заметил вот где. Открылась форма - смотрю память - 12252. Закрываю ShowMessage. Не создавая и не уничтожая объектов повторяю просмотр памяти - опс - 12284, еще и еще и еще смотрю память(объекты не трогаем) - 12284.


 
kyn66 ©   (2009-11-16 15:59) [102]

Получается что ShowMessage внес изменения в память и при закрытии не подчистил за собой.


 
Anatoly Podgoretsky ©   (2009-11-16 16:17) [103]

> kyn66  (16.11.2009 15:57:41)  [101]

Вот и эта ветка уже за 100 постов.


 
Leonid Troyanovsky ©   (2009-11-16 16:23) [104]


> kyn66 ©   (16.11.09 15:57) [101]

> >Попробуй повторить создание-разрушение дважды(без уничтожения
> >формы).

> Без разницы.

Как же - без разницы :)
Измерять надо после первого ShowMessage.

> kyn66 ©   (16.11.09 15:59) [102]

> Получается что ShowMessage внес изменения в память и при
> закрытии не подчистил за собой.

Ну, например, класс окна регистрируют не на один показ.

--
Regards, LVT.


 
kyn66 ©   (2009-11-16 16:31) [105]


> Как же - без разницы :)Измерять надо после первого ShowMessage.

Я так и измерял. После первого - 12252, после второго и последующего - 12284, даже не используя объекты(new/dispose)

> Ну, например, класс окна регистрируют не на один показ.

Вот может за счет этого и есть разница. И ею можно принебречь, я имею ввиду судя по данному тесту. Кстати, по совету [94] подключил FastMM, все настроил как показано в http://timokhov.blogspot.com/2007/03/delphi-2007-iii-fastmm.html . Инициализировал указатели и спецом их не уничтожая закрыл форму. Чегость утечки FastMM не показал. Хм, по консольному приложению из примера на сайте показывал.


 
kyn66 ©   (2009-11-16 16:39) [106]

Да, прверил, вместо ShowMessage(IntToStr(AllocMemSize)); заменил на Application.MessageBox(PChar(IntToStr(AllocMemSize)), PChar(""), MB_OK + MB_ICONASTERISK); и все стало на свои места. 12252=12252(до и после)



Страницы: 1 2 3 вся ветка

Форум: "Начинающим";
Текущий архив: 2010.01.10;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.8 MB
Время: 0.007 c
1-1217266456
self.name
2008-07-28 21:34
2010.01.10
как лучше сравнить строки


2-1258432086
&#8467;o&#8467;
2009-11-17 07:28
2010.01.10
Вопрос о переводе кода (CTL_CODE)


15-1257859624
XXL
2009-11-10 16:27
2010.01.10
Чем можно отобразить SVG ?


2-1258632114
Andrewtitoff
2009-11-19 15:01
2010.01.10
ComponentCount


2-1258455286
cxGrid
2009-11-17 13:54
2010.01.10
не могу раскрасить строки cxGrid





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский