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

Вниз

Создание динамической струскуры хранения данных.   Найти похожие ветки 

 
Erik ©   (2004-02-19 16:17) [0]

А решил отказатся от своих любимых динамических масивов. Но Переходить на TList нерешаюсь. Пока думаю воспользоватся следующей конструкцией.
TDynamicArray = class(TObject)
private
FData: Pointer;
FCount: Integer;
procedure SetCount(c: Integer)
protected
FItemSize: Integer;
procedure GetItem(i: Integer; var Result);
procedure SetItem(i: Integer; var value);
public
constructor Create; virtual;
destructor Destroy; override;
property ItemSize: Integer read FItemSize;
property Count: Integer read FCount write SetCount; // Write this to resize array.
property Data: Pointer read FData; // Read-only pointer to data.
end;

constructor TDynamicArray.Create;
begin
inherited Create;
// You have to set FItemSize in the constructor of your descendant classes!
FItemSize := 1;
// Start your array with room for a certain number of elements by setting Count.
Count := 0;
end;

destructor TDynamicArray.Destroy;
begin
// Dispose of the array data.
FreeMem(FData, FCount * FItemSize);
inherited Destroy;
end;

procedure TDynamicArray.SetCount(c: Integer);
begin
// Resize the array by reallocating FData.
FCount := c;
ReAllocMem(FData, FCount * FItemSize);
end;

procedure TDynamicArray.GetItem(i: Integer; var Result);
var
p: Pointer;
begin
if i >= Count then raise Exception.Create("Array index out of bounds.")
else begin
p := FData;
INC(Integer(p), i * FItemSize);
CopyMemory(@Result, p, FItemSize);
end;


 
Семен Сорокин ©   (2004-02-19 16:23) [1]

так чем TList то не нравится, там все это реализовано с гораздо-большими возможностями?


 
Erik ©   (2004-02-19 16:27) [2]

Будет многопользовательский доступ к данным, тоесть много читателей и много писателей. Еще хочется проверять эти данные их основного модуля и если появились изменения отображать(для отладки).
Есть множество возможностей для организации, какую лучше выбрать?
P.S.
В старом варианте переодически вылетал
Exception occured at $004069B4 (Module "System", Procedure "@DynArrayClear", Unit "", Line 0)
А структура была такая
IDStat = (idGive, idSave, idCancel, idFree);

RInd = record
User: Integer;
Id: Integer;
end;

THole = Record
Params: RTKParams;
Stat: IDStat;
end;
TArrHole = Array of THole;
PArrHole = ^TArrHole;
TCounter = Record
UserID: Cardinal;
Hole: TArrHole; //array one user of reservi aeg
end;

FList: Array of TCounter; - это исходная переменая
FLock: TMultiReadExclusiveWriteSynchronizer; - это для обеспечения раздельного доступа.


 
Amoeba ©   (2004-02-19 16:31) [3]

Изобретаем очередной велосипед?
Посмотри на http://home.earthlink.net/~akonshin/delphi_ru.htm


 
Владислав ©   (2004-02-19 16:32) [4]

Появится новый велосипед с квадратными колесами.


 
Тимохов ©   (2004-02-19 16:37) [5]


> Erik © (19.02.04 16:17)

Если записи содержат динамические массивы, строки или интерфейсы, то работать с их памятью напрямую можно только при определенных знаниях.
Если уж очень хочется, то почитай про методы initialize и finalize.

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

Согласен со многими тут - пользуйся TList, создавая элементы методом new и удаляя методом dispose. В этом случае дельфа сама на себя возьмет заботу о дин. массивах, строках и интерфейсах.


 
Тимохов ©   (2004-02-19 16:38) [6]

вот такая работа

> CopyMemory(@Result, p, FItemSize);

может привести при определенных условиях фиг знает к чему.


 
Тимохов ©   (2004-02-19 16:42) [7]


> Будет многопользовательский доступ к данным, тоесть много
> читателей и много писателей. Еще хочется проверять эти данные
> их основного модуля и если появились изменения отображать(для
> отладки).

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


 
Erik ©   (2004-02-19 17:01) [8]

Я заню про проблемы, поскольку проэкт уже реализован и кое как работает, иногда по 4 для подряд! :)
Я у себя Move и пр... использую но получилось ненадежно. :( Так вроде все отладил, но в многопользовательской среде появились проблемы. Причем несразу а через большой промежуток времени. Вот я и решил все радикально поменять. Можно и TList использовать, но все равно придется блок памяти самому распределять. Так какая разница где хранить указатели на эти блоки?


 
Курдль ©   (2004-02-19 17:06) [9]

TList - не панацея. Всего-навсего массив указателей.
Всегда лучше опираться на конструкции более высокого уровня.
Если Вы работаете с объектами - используйте для них TCollection.


 
Erik ©   (2004-02-19 17:23) [10]

To Курдль
Помоему я описал с чем я работаю, объектами у меня и непахнет.

Размышляю я, что и как лучше сделать. Вот и мнениями других специалистов поинтересовался.


 
Тимохов ©   (2004-02-19 17:26) [11]


> Можно и TList использовать, но все равно придется блок памяти
> самому распределять. Так какая разница где хранить указатели
> на эти блоки?

Почитайте кусочек 5 про new и dispose. И вообще не копируйте область памяти - делайте присвоение явно:

sourcerec.f1 := destinationrec.f1;
....
sourcerec.fn := destinationrec.fn;

Это куда надежней.

Если есть проблемы в многопользовательском режиме - надо использвать методы синхронизации - крит. секции, мьютексы или еще что.


 
jack128 ©   (2004-02-19 17:39) [12]


> создавая элементы методом new и удаляя методом dispose.
> В этом случае дельфа сама на себя возьмет заботу о дин.
> массивах, строках и интерфейсах.
Это точно?
То есть такой код
var
p: PString;
begin
New(p);
p^ := StringOfChar("q", 10);
Dispose(p);
end; не приведет к утечке памяти??


 
Erik ©   (2004-02-19 17:42) [13]

To Тимохов
Количество параметров по пременое, занчить и разное количество памяти выделять надо. Зачить одним New необойдешся. Придется еще кусочик прикрепить.


 
Vuk ©   (2004-02-19 17:43) [14]

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

MaxArraySize = $1FFFFFFF;

PByteArray = ^TByteArray;
TByteArray = array [ 0..MaxArraySize ] of byte;

function TCLArray.Get( Index : integer ) : Pointer;
begin
{$ifdef ThreadSafe}
Lock;
{$endif}
CheckIndex( Index );
Result := @PByteArray( FItems )^[ Index * FItemSize ];
end;

procedure TCLArray.Put( Index : integer; Item : pointer );
begin
{$ifdef ThreadSafe}
Lock;
{$endif}
System.Move( Item^, PByteArray( FItems )^[ Index * FItemSize ], FItemSize );
end;



 
Игорь Шевченко ©   (2004-02-19 17:46) [15]


> проэкт уже реализован и кое как работает, иногда по 4 для
> подряд! :)


Замечательный критерий :))


 
Владислав ©   (2004-02-19 17:52) [16]

> jack128 © (19.02.04 17:39) [12]

А что? Должен?


 
Курдль ©   (2004-02-19 18:00) [17]


> To Курдль
> Помоему я описал с чем я работаю, объектами у меня и непахнет.
>
> Размышляю я, что и как лучше сделать. Вот и мнениями других
> специалистов поинтересовался.


Я, конечно, не специалист, но мне сдается, что Вы - засланный казачок из сей каких-нить. :)
Вы полностью подменяете обязанности компиллятора высокого уровня по заботе о выделении, размещении, освобождении памяти и т.п.
Если хотите, чтобы все супер-быстро работало - вернитесь за си и вперед! А если пишете на ЭТОМ - пользуйтесь ЕГО прелестями.
По существу. Вы предположили поработать с TList.
Я рекомендую TCollection. По сути своей это ничего не меняет - какие-то указатели, указатели на функции, указатели на указатели и т.п. Однако в design-time это даст огромные преимущетсва. Например, ссылки по индексам не только к объектам, но и к их свойствам; автоматическое добавление объектов вместе со всеми их причиндалами по Add, освобождение памяти по Free и т.п. Разве это плохо?


 
Юрий Зотов ©   (2004-02-19 18:01) [18]

> Erik © (19.02.04 16:27) [2]
> Будет многопользовательский доступ к данным, тоесть много
> читателей и много писателей

TThreadList. И все. Уже готовое. Без велосипедов.


 
Тимохов ©   (2004-02-19 18:04) [19]


> jack128 © (19.02.04 17:39) [12]
>
> var
> p: PString;
> begin
> New(p);
> p^ := StringOfChar("q", 10);
> Dispose(p);
> end; не приведет к утечке памяти??

Утечки не будет, т.к. pstring типизированный указатель.


 
Vuk ©   (2004-02-19 18:08) [20]

to Юрий Зотов:
TThreadList, оно, конечно, хорошо, но там защита экземпляра целиком. Иногда лучше иметь защиту на уровне методов. К тому же, насколько я понимаю, стоит задача работать с данными любого размера, а не только с указателями. Так что велосипед иной раз может и пригодиться.


 
VLAD-MAL   (2004-02-19 18:10) [21]

Фундаментальные алгоритмы и структуры данных в Delphi
The Tomes of Delphi Algorithms and Data Structures
Джулиан Бакнелл

Цена: 278 руб.

На складе.
Вес: 510 грамм


Мягкая обложка, 560 стр., 2003 г.
Издательство: ДиаСофтЮП
ISBN 5-93772-087-3, 1-55622-736-1, Тираж: 3000 экз., Формат: 70x100/16

Афигенная книга!


 
jack128 ©   (2004-02-19 18:13) [22]


> Владислав © (19.02.04 17:52) [16]
> > jack128 © (19.02.04 17:39) [12]
>
> А что? Должен?
Это зависит от того файнализирует ли Dispose строку. Вот
> Тимохов © говорит, что все ок.

> Тимохов © (19.02.04 18:04) [19]
А можно ссылку на хелп где это написано? ;-) Или ты это в asm коде высмотрел??


 
Тимохов ©   (2004-02-19 18:16) [23]


> jack128 © (19.02.04 18:13) [22]

Глянь finalize+f1


 
Юрий Зотов ©   (2004-02-19 18:16) [24]

> Vuk © (19.02.04 18:08) [20]

Разве защита внутри Add, Insert, Remove и пр. - это не защита на уровне методов?

Разве работа с указателями - это не работа с данными любого размера?

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


 
Тимохов ©   (2004-02-19 18:23) [25]


> Тимохов © (19.02.04 18:16) [23]

Я тут посмотрел сам куда Вас послал и был удивлен следующей фразой оттуда

Dynamic arrays can never be deallocated using the Dispose procedure, but can be freed by passing them to Finalize.

Не полнял я ее, что-то. В реальности dipose корректно освобождает и дин. массивы. О чем тут речь? Может вы лучше английский знаете?


 
Тимохов ©   (2004-02-19 18:24) [26]


> Юрий Зотов © (19.02.04 18:16) [24]

Вы, конечно, знаете, но все же замечу TThreadList не позволяет одновременное чтение.


 
Vuk ©   (2004-02-19 18:24) [27]

to Юрий Зотов:
>Разве защита внутри Add, Insert, Remove и пр. - это не защита на
>уровне методов?
"Недобросовестный" код может легко развалить защиту TThreadList. Достаточно вызвать LockList, запомнить ссылку, потом UnlockList. Все, с полученной ссылкой можно делать все что душе угодно невзирая на то, что происходит в других потоках.

>Разве работа с указателями - это не работа с данными любого
>размера?
4 байта. :o) А если мне нужен, например, список указателей на методы? Мне выделять вагон блоков по 8 байт в куче или лучше все-таки хранить их в некоем подобии динамического массива?


 
Владислав ©   (2004-02-19 18:24) [28]

> jack128 © (19.02.04 18:13) [22] & Тимохов © (19.02.04 18:16) [23]

Есть еще один способ :)

procedure TForm1.Button1Click(Sender: TObject);
var
p: PString;
i: Integer;
begin
for i := 1 to 100000 do
begin
New(p);
p^ := StringOfChar("q", 100000);
Dispose(p);
end
end;


 
Тимохов ©   (2004-02-19 18:26) [29]


> Владислав © (19.02.04 18:24) [28]
> > jack128 © (19.02.04 18:13) [22] & Тимохов ©

Способ чего?
Каков Ваш тезис?


 
Romkin ©   (2004-02-19 18:27) [30]

Есть велосипед покруче, TMultiReadExclusiveWriteSynchronizer
одно название чего стоит :)))
Это для тех, кто любит одновременное чтение :)


 
Serginio666   (2004-02-19 18:32) [31]

2 VLAD-MAL (19.02.04 18:10) [21]
Книга расчудеснейшая, только тираж маловат.


 
Владислав ©   (2004-02-19 18:32) [32]

> Vuk © (19.02.04 18:24) [27]

"4 байта. :o) А если мне нужен..."

Это точно...

А вообще-то, я в [4] имел ввиду несколько иное.
Написать "свой" TList или TThreadList под конкретный тип данных, чтобы оптимизировать обращение к ним... Полностью согласен, если овчинка выделки стоит... А вот писать такое обобщенное хранилище, ИМХО, только для общего развития. Где еще можно так "наколоться" или перечитать столько различной документации, чтобы хоть что то заработало?


 
Владислав ©   (2004-02-19 18:35) [33]

> Тимохов © (19.02.04 18:26) [29]

На моей конфигурации просто нет столько памяти, чтобы работа этой процедуры завершилась корректно ;)

> Romkin © (19.02.04 18:27) [30]

Ну дык у этого "велосипеда" есть более короткое и более непонятное "название" ;)


 
Vuk ©   (2004-02-19 18:36) [34]

to Владислав:
>А вот писать такое обобщенное хранилище, ИМХО, только для общего
>развития.
Ну не знаю. В работе очень даже помогает. Пример со списком методов - из реальной жизни.


 
Владислав ©   (2004-02-19 18:41) [35]

> Vuk © (19.02.04 18:36) [34]

Как не крути, с типизированными "штуками" позже работать проще, а то, что помогает, ни сколько не спорю.


 
Vuk ©   (2004-02-19 18:43) [36]

to Владислав:
>с типизированными "штуками" позже работать проще
Кто бы спорил, только вот динамические массивы для этого не совсем удобны.


 
Владислав ©   (2004-02-19 18:48) [37]

> Vuk © (19.02.04 18:43) [36]

Почти сдаюсь :) В точку бьете ;) Хотя, в принципе, в [32] я об этом если не сказал, то обмолвился точно :)


 
Serginio666   (2004-02-19 18:58) [38]

2 Vuk ©
Реализация типизированного TList (StringList) на динамическом массиве это пара минут. Все что нужно это Count (капасити это Length), SetLength да правильно использовать Move , не забывая обниливать без вызова финализатора объеты поддерживающих подсчет ссылок.


 
Тимохов ©   (2004-02-19 18:58) [39]


> Владислав © (19.02.04 18:35) [33]
> > Тимохов © (19.02.04 18:26) [29]
>
> На моей конфигурации просто нет столько памяти, чтобы работа
> этой процедуры завершилась корректно ;)

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


 
Vuk ©   (2004-02-19 19:01) [40]

Для примера. Вот код, который реализует список методов с минимальным сервисом (добавление/удаление/доступ к элементам) на основе того класса, фрагменты которого я приводил. Все вполне типизировано.


type
TMethodList = class(TObject)
private
FMethods: TCLArray;
function GetMethods(index: integer): TMethod;
procedure SetMethods(Index: integer; Value: TMethod);
function GetCount: integer;
public
constructor Create;
procedure Add(Handler : TMethod);
procedure Remove(Handler : TMethod);
procedure Delete(Index: integer);
property Count: integer read GetCount;
property Methods[index:integer]: TMethod read GetMethods write SetMethods;
end;

constructor TMethodList.Create;
begin
inherited Create;
FMethods := TCLArray.Create(10, 10, sizeof(TMethod));
end;

procedure TMethodList.Add(Handler : TMethod);
begin
FMethods.Add(@Handler);
end;

function TMethodList.GetMethods(index: integer): TMethod;
begin
Result := TMethod(FMethods.Items[index]^);
end;

procedure TMethodList.Remove(Handler : TMethod);
var
i : integer;
begin
i := FMethods.IndexOf(@TMethod(Handler));
if i <> -1 then
FMethods.Delete(i);
end;

procedure TMethodList.Delete(Index: integer);
begin
FMethods.Delete(Index);
end;

procedure TMethodList.SetMethods(Index: integer; Value: TMethod);
begin
FMethods.Items[index] := @Value;
end;

function TMethodList.GetCount: integer;
begin
Result := FMethods.Count;
end;


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



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

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

Наверх




Память: 0.58 MB
Время: 0.016 c
14-6202
Calm
2004-02-11 09:47
2004.03.03
Готовимся к переходу на Аду?


1-6036
Владимир Березин
2004-02-17 18:45
2004.03.03
Мониторинг состояния Thread а


1-6018
fROT
2004-02-19 12:07
2004.03.03
ivalid class typecast


1-6118
Opryshok
2004-02-19 18:36
2004.03.03
IDispatch реализация без TypeLibrary. Возможно?


14-6182
Makhanev A.S.
2004-02-12 11:01
2004.03.03
TDWebBrowserEvents vs ServiceApplication...