Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.07.25;
Скачать: CL | DM;

Вниз

Как работать с динамическими записями.   Найти похожие ветки 

 
MegaVolt   (2002-07-11 16:49) [0]

В ниже приведённом примере я пытался создать пример для работы с динамическими записями но возникли некоторые проблемы при попытке удаления второго списка т.к. при его создании я не копировал реальные данные а скопировал только указатели на них и когда я удалил первый список то все данные перестали существовать но во втором списке на них остались указатели.
Вопросы:
Как правильно копировать именно данные между:
1. PData и PData
2. PData и TData
3. TData и PData
4. TData и TData
Заранее благодарен :)


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

TsData=record
List:TList;
Str:string;
end;

TData=packed record
Test: Int64;
Attributes: DWORD;
Name: String;
end;

PData= ^TData;

var
Form1: TForm1;
MyList1,MyList2:TsData;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
MyList1.List:=TList.Create;
MyList2.List:=TList.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
z:PData;
begin
//Создаём динамический массив:
For i:=1 to 1000000 do
begin
New(z);
z^.Attributes:=123456;
z^.Test:=98765432;
z^.Name:="Help me";
MyList1.List.Add(z);
end;
ShowMessage("Ok");
end;

procedure TForm1.Button2Click(Sender: TObject);
var
i:integer;
z:PData;
begin
//Копируем из первого списка во второй;
For i:=1 to 1000000 do
begin
z:=MyList1.List[i-1];
MyList2.List.Add(z);
end;
ShowMessage("Ok");
end;

procedure TForm1.Button3Click(Sender: TObject);
var
z:PData;
begin
//удаляем оба массмва:
while MyList1.List.Count<>0 do
begin
z:=MyList1.List[MyList1.List.count-1];
Dispose(z);
MyList1.List.Delete(MyList1.List.Count-1);
end;
while MyList2.List.Count<>0 do
begin
z:=MyList2.List[MyList2.List.count-1];
Dispose(z);
MyList2.List.Delete(MyList2.List.Count-1);
end;
ShowMessage("Ok");
end;

end.


 
Digitman   (2002-07-11 17:02) [1]

procedure TForm1.Button3Click(Sender: TObject);
var
z:PData;
begin
//удаляем оба массмва:
while MyList1.List.Count<>0 do
begin
z:=MyList1.List[MyList1.List.count-1];
Dispose(z);
MyList1.List.Delete(MyList1.List.Count-1);
end;
while MyList2.List.Count<>0 do
begin
z:=MyList2.List[MyList2.List.count-1];
// Dispose(z); // !!!! зачем ??? записи уже уничтожены
MyList2.List.Delete(MyList2.List.Count-1);
end;
ShowMessage("Ok");
end;


 
MegaVolt   (2002-07-11 17:06) [2]

Так удаляю я правильно т.к. я считаю что это отдельные данные. Я в данном примере не правильно копирую :( Вот я и спрашиваю как правильно скопировать а не удалять. У меня при копировании копируется только указатель а нужно чтобы данные. Пример лишон практического смысла кроме демонстрации :)


 
Skier   (2002-07-11 17:10) [3]

>MegaVolt



 
Skier   (2002-07-11 17:12) [4]

>MegaVolt

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


Нужно использовать разадресацию (^) чтобы копировать данные.


 
MegaVolt   (2002-07-11 17:18) [5]

Так на примере нельзя написать ведь похоже всего одна строчка пли-из :)


 
Digitman   (2002-07-11 17:19) [6]

procedure TForm1.Button2Click(Sender: TObject);
var
i:integer;
src, dst :PData;
begin
//Копируем из первого списка во второй;
For i:=1 to 1000000 do
begin
src:=MyList1.List[i-1];
New(dst);
dst^ := src^;
MyList2.List.Add(dst);
end;
ShowMessage("Ok");
end;


 
MegaVolt   (2002-07-11 17:27) [7]

Спасибо приогромное :):):):):)


 
valery_f   (2002-07-11 17:30) [8]

> MegaVolt © (11.07.02 17:06) ...Я в данном примере не правильно копирую...

Точно... Во-первых, нужно создать новую запись и копировать в нее (а не копировать указатель). А во-вторых, когда бежишь по готовому списку, то лучше идти от нуля до Count-1, а не полагаться на константы (это так, правило хорошего тона :) В общем:

procedure TForm1.Button2Click(Sender: TObject);
var i:integer; z:PData;
begin
//Копируем из первого списка во второй;
For i:=0 to MyList1.Count-1 do begin
New(z);
z^ := PData(MyList1.List[i])^;
MyList2.List.Add(z);
end;
ShowMessage("Ok");
end;

а что касается уничтожения, то вызывать Delete для каждого элемента - нехорошо, т.к. на каждое удаление TList"у прийдется перераспределять хранилище указателей. т.е. удаление лучше сделать так:

for i := 0 to MyList1.List.Count-1 do begin
z:=MyList1.List[i];
Dispose(z);
end;
MyList1.Clear;

или, если удаляешь не все элементы:

for i := 0 to MyList1.List.Count-1 do begin
z:=MyList1.List[i];
if надо then begin
Dispose(z);
MyList1.List[i] := nil;
end;
end;
MyList1.Pack;


 
MegaVolt   (2002-07-12 10:20) [9]

Спасибо за добавление но что такое констаны на которые я ссылаюсь?
При удалении вы ты предлагаешь применять метод Pack но он если верить справке удаляет только те указатели которые=nil и соответственно для этого нужно применять не Dispose а FreeAndNil или я не прав?


 
valery_f   (2002-07-12 11:54) [10]

> MegaVolt © (12.07.02 10:20) ...что такое констаны на которые я ссылаюсь?

При копировании списка ты задаешь цикл "For i:=1 to 1000000", т.е. полагаешься на то, что ты точно знаешь сколько там чего. Это не очень то правильно, т.к. начнешь ты что-то в программе менять, и прийдется тебе лазить по всему исходнику и искать все свои "1000000". Учитывая, что TList имеет св-во Count, лучше использовать его (см. мой пример). В общем, вырабатывай правильный стиль, в сложных проектах без этого никак (замахаешься отлаживать :).

>...метод Pack но он если верить справке удаляет только те указатели которые=nil

Совершенно верно. Сначала я 1) уничтожаю объекты и выставляю указатели на них в nil, а потом 2) одним махом удаляю все пустые указатели. Еще раз - TList при выполнении Delete перераспределяет память, и у тебя это происходит на каждой итерации, что снижает быстродействие, а у меня только один раз. Вот и вся разница.

> ...для этого нужно применять не Dispose а FreeAndNil

Ну, во-первых не путай работу с объектом и работу с указателем. В моем примере сначала зовется Dispose для удаления записи, и затем указатель сбрасывается в nil (это если собираешься юзать метод Pack, если Clear - сбрасывать указатель необязательно). Во-вторых, FreeAndNil работает только с объектами (см. реализацию FreeAndNil в sysutils), но никак не с записями, и потому здесь неприменим.


 
Yuri-7   (2002-07-12 13:34) [11]

>valery_f
Зачем для TList удалять все элементы индивидуально?
В Help написано, что метод Clear и так это делает.


 
valery_f   (2002-07-12 13:43) [12]

> Yuri-7 (12.07.02 13:34) В Help написано, что метод Clear и так это делает.

Clear удаляет память, используемую для хранения указателей (!), а ссылаются ли удаляемые указатели на что-то или нет - ему глубоко пополам.


 
Yuri-7   (2002-07-12 14:34) [13]

> valery_f
Посмотри в classes.pas, как выполняется Clear!


 
Skier   (2002-07-12 14:59) [14]

>Yuri-7
Ты не прав !


 
valery_f   (2002-07-12 15:04) [15]

> Yuri-7 (12.07.02 14:34) Посмотри в classes.pas, как выполняется Clear!

Да, ты прав - Clear зовет SetCount(0), а там для каждого элемента - Delete (по крайней мере в D6). А учитывая, что ты удаляешь с конца списка - перемещения массива указателей не просходит. Твоя процедура очистки корректна.

Правда непонятно, зачем внутри Clear борланд поставил удаление для каждого элемента. Вполне хватило бы:

procedure TList.Clear;
begin
FCount := 0;
SetCapacity(0);
end;

Ну да ладно... С копированием-то разобрался?


 
Skier   (2002-07-12 15:07) [16]

>valery_f
Это только для D6 ?


 
Skier   (2002-07-12 15:16) [17]

>Yuri-7
Я имел ввиду что Clear не убивает данные "по указателям".
Он только освобождает память выделенную под указатели...

Если не так тебя понял - извини.


 
valery_f   (2002-07-12 15:21) [18]

> Skier © (12.07.02 15:07) Это только для D6 ?

У меня сейчас стоит только шестерка. Загляни в classes... правда, скорее всего, в остальных версиях то же самое. Сорцы - очень интересное место, т.к. когда вдруг обнаруживаешь как оно работает на самом деле... :))))


 
Skier   (2002-07-12 15:24) [19]

>valery_f
Да. Я смотрел и в D5 то же самое :

в TList.SetCount есть такой кусок:

for I := FCount - 1 downto NewCount do Delete(I);

Ты его имел ввиду ?


> Сорцы - очень интересное место


И к тому же весьма поучительное :)


 
Yuri-7   (2002-07-12 15:34) [20]

>skier
Я то имею ввиду, что и данные "убиваются" по указателям. И в D5 и в D6


 
Skier   (2002-07-12 15:36) [21]

>Yuri-7
???
Приведи кусок где это происходит.


 
Yuri-7   (2002-07-12 16:00) [22]

>skier
Виноват, похоже, что процедура Notify у них зарезервирована для будущего использования.


 
Skier   (2002-07-12 16:01) [23]

>Yuri-7
Ну....тогда смотри Skier © (12.07.02 14:59) :))


 
valery_f   (2002-07-12 16:16) [24]

> Yuri-7 (12.07.02 16:00) ...похоже, что процедура Notify у них зарезервирована для будущего использования.

Не для будущего, а для твоего, если тебе нужно будет создать своего собственного специализированного потомка TList"а.


 
чайнчек   (2002-07-12 20:00) [25]

Просветите, чем отличаются обращения к полям записи:
z^.Attributes:=123456;
и
z.Attributes:=123456;
Компилятор принимает оба варианта. И оба работают.
Ведь при обращении к полям объекта мы не пишем VarObject^.Field1
потому как любая объектная переменная по сути своей - указатель.


 
чайничек   (2002-07-12 20:01) [26]

Просветите, чем отличаются обращения к полям записи:
z^.Attributes:=123456;
и
z.Attributes:=123456;
Компилятор принимает оба варианта. И оба работают.
Ведь при обращении к полям объекта мы не пишем VarObject^.Field1
потому как любая объектная переменная по сути своей - указатель.


 
Zazoo   (2002-07-13 01:08) [27]

> чайничек

В с++ есть такой оператор "->", он раименовывает указатель и выдирает из соответствующего объекта поле/метод(аналог objptr^.item). В Делфи этот оператор(доступ к члену класса по укзателю на объект) обозначается ".", поэтому компилятор понимает оба варианта.

> любая объектная переменная по сути своей - указатель
Вообще с классами в Делфи не все понятно: с одной стороны это именно объект(передается в функции как копия), а с другой - указатель.


 
Случайный прохожий   (2002-07-14 12:18) [28]


> Zazoo © (13.07.02 01:08)


> с одной стороны это именно объект(передается в функции как
> копия)

Никогда. Передается только указатель.



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

Текущий архив: 2002.07.25;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.017 c
1-81248
nwc_eminem
2002-07-14 18:20
2002.07.25
Как записать в реестор значение параметра


14-81476
Axel
2002-06-28 16:26
2002.07.25
Прежде, чем завести ребенка...


14-81418
mcs
2002-06-27 09:48
2002.07.25
Свен Шрайбер


3-81176
Still Swamp
2002-06-24 17:11
2002.07.25
Service + MSSql


14-81452
JohnnyJ
2002-06-23 04:18
2002.07.25
<<< Ф У Т Б О Л >>>