Форум: "Основная";
Текущий архив: 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)
Страницы: 1 2 вся ветка
Форум: "Основная";
Текущий архив: 2004.03.03;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.006 c