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

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.007 c
1-81368
Nick 007
2002-07-14 00:50
2002.07.25
Командная строка...


3-81132
Виталий Панасенко
2002-07-03 14:16
2002.07.25
D1+D5


14-81455
Sasha9
2002-06-27 15:43
2002.07.25
Win


14-81474
Ricks
2002-06-29 01:35
2002.07.25
Формат PNG


1-81328
perseptron
2002-07-12 18:04
2002.07.25
Срочно!





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский