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

Вниз

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

 
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)


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

> Тимохов © (19.02.04 18:58) [39]

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

> Vuk © (19.02.04 19:01) [40]

Оценил бы, да понятия не имею, что такое TCLArray. Просветите плиз.


 
romeo   (2004-02-19 19:12) [42]


> Тимохов © (19.02.04 17:26) [11]

CopyMemory плохо только в этом случае, или лучше вообще этим не пользоваться? Например, для копирования значений из одного массива в другой, типа:

var
DinArr: array of integer;
const
Arr: array [0..50] of integer = (1, ...);

SetLength(DinArr, Length(Arr))
CopyMemory(DinArr, @Arr, Length(Arr)*SizeOf(Integer))


Или тоже лучше делать почленное копирование?


 
Владислав   (2004-02-19 19:15) [43]

В данном случае ничего плохого не произойдет. Правда всегда есть оговорка ;) Вот она: Если, например, к типу Integer не преобразованы указатели на переменные типа string ;)


 
Vuk   (2004-02-19 19:16) [44]

to Владислав:
>Просветите плиз.
Привожу только интерфейс. Полный код - это слишком много. Писалось сие давно, поэтому по интерфейсу и реализации это что-то среднее между TList и коллекциями из Turbo Pascal (касается управления памятью).

TCLArray = class( TCLContainer )
protected
FCount : integer;
FLimit : integer;
FDelta : Integer;
FItemSize : integer; { размер одного элемента }
FItems : Pointer; { указатель на непрерывный блок памяти, содержащий элементы массива }

function Get( Index : integer ) : Pointer; override;
procedure Put( Index : integer; Item : Pointer ); override;
function GetCount: integer; override;
procedure AssignTo( Dest : TPersistent); override;
procedure AppendItem( Item : pointer; AssignMode : boolean ); override;
procedure SetLimit( ALimit : integer ); virtual;
procedure CheckIndex( Index : integer );
procedure SetCount( NewCount : integer );
procedure IndexError;

public
constructor Create( ALimit, ADelta, AItemSize : Integer );
destructor Destroy; override;
procedure Add( Item : pointer ); override;
procedure Clear; override; {обнуление всех элементов}
procedure Swap( Index1, Index2 : integer ); override;
procedure Insert( Index : integer; Item : pointer );
function IndexOf(Item: pointer): integer; override;
procedure Delete( Index : integer ); override;
procedure DeleteAll; override; {удаление всех элементов}

property Items;
property Count : integer read FCount write SetCount;
property Limit : integer read FLimit write SetLimit;
property Delta : integer read FDelta write FDelta;
property ItemSize : integer read FItemSize;
property Data : pointer read FItems;
end;


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


> Владислав © (19.02.04 19:15) [43]


> Если, например, к типу Integer не преобразованы указатели
> на переменные типа string ;)

Глубоко копаете. Но в случае если это указатели, преобразованные к integer, никакого подсчета ссылок и для почленного копирование не будет.

> romeo © (19.02.04 19:12) [42]

Для массивов integer все будет ок.


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

> Тимохов © (19.02.04 19:18) [45]

Смайлик, однако...

Подсчета ссылок не будет. Будет, как пить дать, обращение по битым ссылкам (это относится только к вашему утверждению. Типа, почти оффтоп).

> Vuk © (19.02.04 19:16) [44]

Ну судя по приведенному, именно не типизированное, приведенное в типизированное :) Типа, одобрям :) Надо взять на заметку.
А вот это ADelta (если я правильно понял) просто здорово. Чего, боюсь, автору вопроса очень не хватает. В общем, очень интересно!


 
Vuk   (2004-02-19 19:34) [47]

>А вот это ADelta (если я правильно понял) просто здорово.
Delta - это значение (в элементах массива), на которое увеличивается размер массива при вызовах Add и Insert, если количество элементов уже достигло максимально возможного на данный момент (limit). В TList происходит то же самое, но регулировать величину приращения нельзя - она вычисляется автоматически. В принципе, обе стратегии выделения памяти имеют право на существование. Если бы я писал сейчас, то у меня Delta задавалась бы в процентах от текущего размера.


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

> Vuk © (19.02.04 19:34) [47]

"...задавалась бы в процентах от текущего размера."

Ну да, конечно, но зависит, таки от конкретной задачи. Я у себя отказался от ТАКОГО "расширения". Проценты "увеличивают" размер занимаемой памяти каждый раз на все большую величину. Я в своей задаче не знал, как он будет увеличиваться. Остановился на таком варианте. Сначала проценты (до некоторого размера), потом жестко заданный прирост.

Насчет дельты, надеюсь, Вы меня поняли :)


 
Vuk   (2004-02-19 20:10) [49]

to Владислав:
>Насчет дельты, надеюсь, Вы меня поняли
Ну... В принципе, для таких вещей можно сделать что-то типа отдельных классов, которые реализуют разные стратегии управления памятью, а класс-массив уже использует какой-то из таких классов для своей работы. Тогда можно будет реализовать сколько угодно таких стратегий и даже менять их налету. :o)



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

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

Наверх





Память: 0.59 MB
Время: 0.007 c
3-5950
snake7
2004-02-06 16:33
2004.03.03
Работа ч/з ADO 2


1-6061
BlackTiger
2004-02-17 18:10
2004.03.03
Как узнать ПРЕДЫДУЩИЙ активный контрол?


1-6131
Gnusik
2004-02-19 19:05
2004.03.03
Создание ярлыка в Win XP


14-6188
Анонимщик
2004-02-11 14:45
2004.03.03
Шахматы


1-6138
Harm
2004-02-19 16:34
2004.03.03
Последний день месяца





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