Помощь - Поиск - Пользователи - Календарь
Полная версия: TList
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Free Pascal, Pascal ABC и другие
compiler
Добрый день
Существует ли список в FP, как встроенный тип?
говорят что да но найти о нем в руководстве не могу ни слова sad.gif
volvo
Не совсем "встроенный". Описан в модуле Classes... А информация о нем - в файле ref.pdf: "Chapter 2.46 TList"

Также может быть полезно посмотреть про TFPList (в разделе 2.42 того же файла), поскольку
Цитата
Contrary to TList, TFPList has no notification mechanism. If no notification mechanism is used, it is better to use TFPList instead of TList, as the performance of TFPList is much higher.
compiler
спасибо...
а что такое notification mechanism?


Добавлено через 5 мин.
а всетаки в документации найти не могу... у меняв Reference guide for Free Pascal, version 2.0.4 Document version 2.0тут Chapter 2 это про Сonstants...
volvo
Документация утверждает ,что у TList-а есть механизм, позволяющий сообщать об изменениях, произошедших в списке, что может замедлить общее быстродействие. Правда, где бы не встречалось упоминание этого самого "notification mechanism", везде говорится в таком стиле: "не знаю, что это такое, никогда не пользовался этим, однако оно есть".

Я вот тоже не пользовался (а может, и пользовался, только не знаю, что это так называется) - просто предупреждаю, о том, о чем написано в доках.

Добавлено через 1 мин.
P.S.
Сорри, это не ref.pdf, а RTL.pdf, естественно...
compiler
мда... ихний список совсем не список... мне совсем непонятно как им пользоваться, смотрел дукументацию ( где нет ни одного примера ), исходники, был на оф. сайте, все равно не понял... может у кого есть простенький пример показывающий его использывывание?
volvo
А может лучше ты расскажешь, что хочешь получить? А то знаешь ли, примеры могут быть разные, вдруг тебе СОВСЕМ не это надо? Чего хранить-то хочешь, вообще? Сохранил, что потом делать с данными?
compiler
Цитата(volvo @ 15.07.2007 18:37) *
А может лучше ты расскажешь, что хочешь получить? А то знаешь ли, примеры могут быть разные, вдруг тебе СОВСЕМ не это надо? Чего хранить-то хочешь, вообще? Сохранил, что потом делать с данными?

в каждой ячейке списка у меня должно быть указатель на следующий элемент либо nil, если это последний элемент, пользовательский тип и, возможно, переменная -- указывывающая порядковый номер ячейки. Список должен , методами добавления/удаления новых ячеек с обоих сторон списка(обладать конструктором/деструктором для отдельных ячеек), методами доступа к полям любой из ячеек , может еще что-то. Все должно иметь возможность выполняться имея лишь указатель на ячейку.
volvo
Цитата
в каждой ячейке списка у меня должно быть указатель на следующий элемент либо nil, если это последний элемент
Все, про TList можешь забыть - реализуй список сам...

Пойми: вместо того, чтобы как в каменном веке реализовывать список с нуля, тебе предлагают уже готовый контейнер для хранения указателей (в TVision это называется "коллекция"), позволяющий тебе искать элементы, сортировать, производить над каждым из них (или над теми, которые удовлетворяют какому-либо условию, это уже как реализуешь) какие-то действия... А ты вместо этого хочешь хранить "указатель на следующий элемент", и делать все вручную? Тогда делай вручную...
compiler
Цитата(volvo @ 15.07.2007 19:58) *

Все, про TList можешь забыть - реализуй список сам...

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

просто как работать с классическим списком я читал, а как с таким даже не представляю... указатель мне нужен просто что б как-то обращаться именно к этому элементу...
hardcase
Цитата(compiler @ 15.07.2007 21:09) *

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

TList скорее ближе по духу к массиву.
Классический список прдоставляет последовательный доступ к элементам, тогда как TList позволяет ображаться к содержимому по индексу, грубо говоря, TList внутри себя содержит массив элементов, над которым происходят действия типа Insert, Delete и т.д.
compiler
А простым примером по использовыванию никто не поделиться?
volvo
Так, например:

uses classes;

type
PT = ^T;
T = record
X, Y: integer;
end;

function compare(a, b: pointer): integer;
begin
if PT(a)^.X > PT(b)^.X then compare := 1
else
if PT(a)^.X < PT(b)^.X then compare := -1
else compare := PT(a)^.Y - PT(b)^.Y;
end;
procedure print(p: pointer);
begin
with PT(p)^ do begin
writeLn('X = ', X:2, ' Y = ', Y:2);
end;
end;
procedure incr(p: pointer);
begin
with PT(p)^ do begin
inc(X); inc(Y);
end;
end;

var
p: PT;
my_list: TFPList;
i: integer;

begin
my_list := TFPList.Create();
for i := 1 to 10 do begin
new(p);
with(p^) do begin
X := random(15); y := random(15);
writeLn('X = ', X:2, ' Y = ', Y:2);
end;
my_list.add(p);
end;

writeln('for each');
my_list.foreachcall(@incr, nil);
my_list.foreachcall(@print, nil);
writeln('sorting');
my_list.sort(@compare);
my_list.foreachcall(@print, nil);

// здесь удалить все элементы и сам список

end.

compiler
volvo, а в каком режиме ты компилировал?
мой лог
Код
ex.pas(47,28) Error: Incompatible type for arg no. 1: Got "<address of procedure(Pointer);Register>", expected "<procedure variable type of procedure(Pointer, Pointer);Register>"
ex.pas(48,29) Error: Incompatible type for arg no. 1: Got "<address of procedure(Pointer);Register>", expected "<procedure variable type of procedure(Pointer, Pointer);Register>"
ex.pas(51,29) Error: Incompatible type for arg no. 1: Got "<address of procedure(Pointer);Register>", expected "<procedure variable type of procedure(Pointer, Pointer);Register>"
ex.pas(55,4) Fatal: There were 3 errors compiling module, stopping
ex.pas(55,4) Fatal: Compilation aborted

если использовать {$mode objfpc}, то на одну ошибку меньше smile.gif
volvo
У меня по умолчанию выставлен {$mode delphi}
compiler
Цитата(volvo @ 17.07.2007 14:56) *
У меня по умолчанию выставлен {$mode delphi}
[оффтоп]а у меня диалект...[/оффтоп] спасибо, так все компилируется, теперь будем разбираться...
volvo
Для диалекта - надо добавить кое-что в заголовки процедур:
{$mode objfpc}
uses classes;

type
PT = ^T;
T = record
X, Y: integer;
end;

function compare(a, b: pointer): integer;
begin
if PT(a)^.X > PT(b)^.X then compare := 1
else
if PT(a)^.X < PT(b)^.X then compare := -1
else compare := PT(a)^.Y - PT(b)^.Y;
end;
procedure print(p: pointer; arg: pointer); // Еще один параметр
begin
with PT(p)^ do begin
writeLn('X = ', X:2, ' Y = ', Y:2);
end;
end;
procedure incr(p: pointer; arg: pointer); // И здесь тоже ...
begin
with PT(p)^ do begin
inc(X); inc(Y);
end;
end;

var
p: PT;
my_list: TFPList;
i: integer;

begin
my_list := TFPList.Create();
for i := 1 to 10 do begin
new(p);
with(p^) do begin
X := random(15); y := random(15);
writeLn('X = ', X:2, ' Y = ', Y:2);
end;
my_list.add(p);
end;

writeln('for each');
my_list.foreachcall(@incr, nil);
my_list.foreachcall(@print, nil);
writeln('sorting');
my_list.sort(@compare);
my_list.foreachcall(@print, nil);

end.

compiler
Цитата(volvo @ 17.07.2007 15:25) *
Для диалекта - надо добавить кое-что в заголовки процедур
я все равно не могу понять способ вызова процедур...
на примере incr
my_list.foreachcall(@incr, nil);//для каждого элемента my_list вызываем эту процедуру
зачем передавать nil?
procedure incr(p: pointer; arg: pointer); 
//получаем 2 аргумента первый указатель на процедуру,
// второй -- не ясно что...
begin
with PT(p)^ do begin // PT(p)^ ? р-- это ж ведь указатель на процедуру, а не на ячейку или список...
inc(X); inc(Y);
end;
end;


volvo
С пониманием природы первого указателя у тебя проблема...
Цитата
получаем 2 аргумента первый указатель на процедуру, второй -- не ясно что...
С чего бы это? Смотри, что написано:

Цитата(rtl.pdf)
2.42.21 TFPList.ForEachCall
Synopsis: Call a procedure or method for each pointer in the list.
Declaration: procedure ForEachCall(proc2call: TListCallback;arg: pointer)
procedure ForEachCall(proc2call: TListStaticCallback;arg: pointer)
Visibility: public
Description: ForEachCall iterates over all pointers in the list and calls proc2call, passing it the pointer and the additional arg data pointer. Proc2Call can be a method or a static procedure.

То есть, первый аргумент - это сам указатель, хранящийся в списке (над элементом, на который он указывает, надо произвести какие-то действия), а второй - дополнительный указатель.

Второй ЗДЕСЬ не используется.
compiler
Цитата(volvo @ 17.07.2007 15:50) *
С чего бы это?
туманно все как-то...

посмотрев исходники кажеться понял зачем nil -- просто так..

my_list.foreachcall(@incr, nil);
//вызов процедуры

procedure incr(p: pointer; arg: pointer); // И здесь тоже ...
//реализация процедуры
begin
with PT(p)^ do begin
inc(X); inc(Y);
end;
end;


procedure TFPList.ForEachCall(proc2call:TListCallback;arg:pointer);
//реализация метода(исходники)
var
i : integer;
p : pointer;
begin
For I:=0 To Count-1 Do
begin
p:=FList^[i];
if assigned(p) then
proc2call(p,arg);
end;
end;

type TListCallback = procedure(
//реализация типа (документация)
data: pointer; //Data pointer from the list.
arg: pointer // Parameter passed to the ForEachCall call. /не нужный параметр?
) of object;

итак мы вызываем метод(в качестве первого параметра используем указатель(почему?) на процедуруа второй оставляем пустым), процедура возвразщает 2 указателя, которые преобразуются в некий TListCallback. Тоесть мы для вызова ForEachCall используем два лишних указателя .Так?
hardcase
TListCallback - это процедура которую будет вызывать ForEachCall для КАЖДОГО элемента списка и передавать ей этот элемент первым параметром.
Втрой указаталь - arg нужен для того, чтобы передавать в TListCallback некие дополнительные параметры, например, если мы хотим отфильтровать список, в качестве arg будет выстпуать новый список, в котором будут аккумулироваться разультаты фильтрации.
volvo
Во-первых, в моем примере используется не TListCallback, а TListStaticCallback, ведь у меня вызываемая процедура не является методом класса. Хотя это не важно, есть 2 версии ForEachCall (для метода класса и для статической процедуры) ...

Цитата
в качестве первого параметра используем указатель <...> на процедуру
Это не указатель на процедуру, а адрес процедуры. Потому что так реализовано.
Цитата
а второй оставляем пустым
Хочешь, я приведу тебе пример, когда тебе понадобится использовать и второй указатель (а не оставлять его пустым)? Ясно же написано: дополнительные данные. Вот попробуй, например, сделать, чтобы при первом вызове процедуры Incr координата X каждой записи, что в списке увеличивалась на 4, а Y - на 8, а при втором вызове - X уменьшалось бы на 3, а Y - увеличивалось на 5. С использованием второго параметра - элементарно (не привлекая глобальных переменных, ибо они - зло)...

Цитата
Тоесть мы для вызова ForEachCall используем два лишних указателя
Если ты считаешь заложенную в реализации гибкость "лишней" - тебя ж никто не заставляет использовать это. Напиши свое, естественно, ты сделаешь это гораздо лучше, правда?
compiler
хорошо, но все же почему мы вызываем(@incr, nil), а не (incr, nil)?
compiler
вопрос по добавлению нового элемент есть метод Add.
Цитата
public function TFPList.Add(Item: Pointer):Integer;
Description
Add adds a new pointer to the list after the last pointer (i.e. at position Count, thus increasing the item count with 1. If the list is at full capacity, the capacity of the list is expanded, using the Grow method.

но как что ему передавать не что он возвращает не указано... так что это за параметры?
volvo
Цитата
так что это за параметры?
На входе - тот самый указатель (на данные), который ты добавляешь в список. На выходе - индекс элемента списка, в который этот указатель был занесен.

Добавлено через 2 мин.
Цитата
почему мы вызываем(@incr, nil), а не (incr, nil)
Потому, что при вызове (Incr, nil) компилятор может посчитать, что ты хочешь передать результат вычисления функции, а не саму функцию как параметр, следовательно, его надо переубедить... А как? Правильно, добавляем @, и двусмысленности не возникает.
compiler
хорошо, вроде разобрались...
спасибо.


compiler
есть задача а не получается smile.gif
существует некий пользовательский класс С, он состоит из нескольких полей, одним из которых является List: TFPList; STATIC;. используя конструктор мы добавляем туда ячейки
{private class} procedure C.Metod2(const Node:TNode);
var
p: ^TNode;
begin
new(p);
p^:=Node;
self.List.Add(p);
end;

, где
TNode = record      
U:UserTipe;;
end;

теперь деструктор
{private class} procedure C.Metod2();
var
SomeU:UserTipe;
begin
SomeU:=self.List[0].TNode.U;//сохраняем поле обьекта <---ОШИБКА!!!
MySnake(MyList[0]).Free; //освобождаем объект
MyList.Delete(0); //удаляем ссылку на него
end;
получаю набор ошибок... в модуле использую {$STATIC ON} и {$mode objfpc}.

что делать?
заранее благодарен.
volvo
Присоедини программу полностью, чтоб ее можно было скомпилировать, и получить те же ошибки что и у тебя, а не заниматься непонятно чем...
compiler
***
volvo
Ну, допустим, для того, чтобы сохранить значение нулевого элемента списка, тебе достаточно сделать:
  SomeU := PUser(List[0])^;
, где PUser = ^UserTipe;

А что дальше у тебя происходит, я не знаю, MySnake не определено...
compiler
Цитата(volvo @ 20.07.2007 15:26) *
Ну, допустим, для того, чтобы сохранить значение нулевого элемента списка, тебе достаточно сделать:
  SomeU := PUser(List[0])^;
, где PUser = ^UserTipe;
спасибо
Цитата(volvo @ 20.07.2007 15:26) *
А что дальше у тебя происходит, я не знаю, MySnake не определено...
MySnake читается как MyC smile.gif

Добавлено через 14 мин.
может я что-то делаю не так, но получаю
Цитата
u4volvo.pas(31,16) Warning: Local variable "PUser" does not seem to be initialized
u4volvo.pas(31,11) Error: Incompatible types: got "^UserTipe" expected "UserTipe"
u4volvo.pas(31,16) Fatal: Syntax error, ";" expected but "(" found
u4volvo.pas(31,16) Fatal: Compilation aborted
volvo
Я же написал:
Цитата
где PUser = ^UserTipe;
, а значит, я имел в виду описание типа PUser, как указателя на UserTipe, но никак не переменной такого типа...
compiler
Цитата(volvo @ 20.07.2007 16:25) *
Я же написал , а значит, я имел в виду описание типа PUser, как указателя на UserTipe, но никак не переменной такого типа...
от этого у меня результат не меняется, только в Incompatible types: got "^UserTipe" expected "UserTipe" вместо "^UserTipe" есть "PUser"...
volvo
Да нельзя делать это с переменной! Нужно приводить к типу:
procedure MyC.Metod2();
type
PUser = ^UserTipe; // <-- Хотя это желательно сделать при описании типа UserTipe, в том же модуле
var
SomeU: UserTipe;
begin
SomeU := PUser(List[0])^;
...
compiler
спасибо теперь эта часть( smile.gif ) работает...
Цитата(volvo @ 20.07.2007 16:39) *
Хотя это желательно сделать при описании типа UserTipe, в том же модуле
Почему?
и еще
{...}implementation{...}
procedure MyC.Metod2();
var
SomeU:UserTipe;
begin
SomeU := PUser(List[0])^; //тут, благодаря тебе, работает..
self.List[0].Free; //а тут нет sad.gif
//необходимо отчищать память где находилось то на что указывал указатель, но как?
self.List.Delete(0);
end;
end.


volvo
Вот что мне непонятно - это твое нежелание использовать ООП везде, а не только где-то... Смотри:

ut.pas
type
PUser = ^UserTipe;
UserTipe = object
x: integer;

destructor done;
end;

implementation

destructor UserTipe.Done;
begin
// Пока можно оставить пустым
end;


Второй файл

...
procedure MyC.Metod2();
var
SomeU: UserTipe;
begin
SomeU := PUser(List[0])^; // Сохраняем данные
Dispose(PUser(List[0]), Done); // Удаляем объект по указателю ...
List.Delete(0); // ... и сам указатель
end;
...

Не нужно Self все время за собой таскать, компилятор и так разберется...

Цитата
Почему?
Именно потому, что типы объекта и указателя на него логически связаны сильнее, чем тип списка и указателя на объект... Да и еще. Мало ли, где тебе придется использовать указатель на объект, что будешь делать - определять несколько раз один и тот же тип указателя?
compiler
одни вопросы smile.gif
Цитата(volvo @ 20.07.2007 18:08) *
Вот что мне непонятно - это твое нежелание использовать ООП везде, а не только где-то...
Так получается smile.gif
Цитата(volvo @ 20.07.2007 18:08) *
Пока можно оставить пустым
Пока? А что потм туда надо будет писать?
Цитата(volvo @ 20.07.2007 18:08) *
Dispose(PUser(List[0]), Done);
а что будет работать быстрее данный способ или c FreeMem и определением размера(хотя его можна задать константой)?
Цитата(volvo @ 20.07.2007 18:08) *
Не нужно Self все время за собой таскать, компилятор и так разберется...
мне так удобней...
Цитата(volvo @ 20.07.2007 18:08) *
Именно потому, что типы объекта и указателя на него логически связаны сильнее, чем тип списка и указателя на объект... Да и еще. Мало ли, где тебе придется использовать указатель на объект, что будешь делать - определять несколько раз один и тот же тип указателя?
убедил smile.gif
volvo
Цитата
мне так удобней...
Мало ли, как тебе удобнее... Ты мало того, что делаешь лишние действия, так еще и рискуешь нарваться на проблемы. Не забывай, что ты работаешь с Class Methods, так что Self может указывать на Object Instance, а может и на VMT...

Кстати, то что я написал не сработает. Вылетит программа с RTE 210... Вот так - работает:
procedure MyC.Metod2();
var
SomeU: UserTipe;
L: PUser;
begin
SomeU := PUser(List[0])^;
writeln(someu.X);

L := List[0];
Dispose(L); // Это удалит все, что надо - проверено с использованием heaptrc

List.Delete(0);
end;

compiler
Цитата(volvo @ 20.07.2007 19:45) *
Не забывай, что ты работаешь с Class Methods, так что Self может указывать на Object Instance, а может и на VMT...
кто такой VMT?
Цитата(volvo @ 20.07.2007 19:45) *
heaptrc
а я с этими дебаргерами так и не разобрался...
hardcase
Цитата(compiler @ 20.07.2007 20:56) *
кто такой VMT?

Virtual methods table - таблица методов класса. Фактически является "объектом класса".
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.