![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Array [0..X] [D4, Win2k]
Kolya © (2002-10-02 02:28:00)Здравствуйте Мастера!
Моя программа работает с array of long. В 90% случаев требуются всего лишь 50-100 переменных, но иногда может потребоватся и несколько тысячь. Мне не хочется создавать array с 5000 переменных, поскольку это будет занимать очень много памяти (5000 x 4b = 20k). Гораздо лучше было бы сделать array с 50 переменными и только в 10% случаев разширять его до 5000. Возможно ли это? Заранее спасибо!
Serg Gurin (2002-10-06 03:47:00) [1]Ответ на заданный вначале вопрос перерос в большую полемику :). Тут я так понимаю столкнулись две ветви программирования, грубо говоря - Basic и Си. Одни говорят пусть тормозит - зато надежно, другие - я пишу круто и без ошибок, поэтому нужно писать что б работало побыстрее. Как мне кажется и те и другие правы на 100%. Лично я исхожу (думаю как и многие из Вас) из посталенной задачи. Если скорость не требуется и железо позволяет - можно писать
for I:=1 to N do
begin
SetLength(DataArray, I);
DataArray[I-1] := Data;
end;
и затем так же обрабатывать
Sum := 0;
for I:=0 to Length(DataArray)-1 do
Sum := Sum + DataArray[I];
надежно и голову забивать не надо в поисках ошибки, а
если требуется скорость, то лучше вообще не пользоваться динамическими массивами, а делать как в старом добром паскале самому
определить типы
type
PLongArray = ^TLongArray;
TLongArray = array [0..(MaxInt div SizeOf(LongInt))-1] of LongInt;
или если хотите
TLongArray = array [0..0] of LongInt;
но тогда в нужном месте (перед обращенем через индекс) нужно поставить {$R-} - отключить проверку на выход за границы массива, если таковой включен (на время отладки :))
var
Count: LongInt;
AllocCount: LongInt;
DataArray: PLongArray;
в нужном месте программы вставить если неясно сколько данных прийдет
ElementSize := SizeOf(LongInt);
AllocCount := 0;
Count := 0;
DataArray := nil;
while Count < N do
begin
if Count >= AllocCount then
begin
AllocCount := AllocCount + 1000;
ReAllocMem(DataArray, AllocCount*ElementSize);
end;
DataArray^[Count] := Data;
Inc(Count);
end;
if AllocCount > Count then
ReAllocMem(DataArray, Count*ElementSize);
или известно их максимальное количество
ElementSize := SizeOf(LongInt);
Count := 0;
DataArray := AllocMem(MaxAllocCount*ElementSize);
while Count < N do
begin
if Count >= MaxAllocCount then
begin
MessageBox(Application.Handle, "Данных пришло все-таки больше :)", "Ошибка!", MB_ICONERROR + MB_OK + MB_SYSTEMMODAL);
Break;
end;
DataArray^[Count] := Data;
Inc(Count);
end;
if MaxAllocCount > Count then
ReAllocMem(DataArray, Count*ElementSize);
и затем пользоваться
Sum := 0;
I:=0;
while I < Count do
begin
Sum := Sum + DataArray^[I];
Inc(I);
end;
в конце не забыть освободить массив
FreeMem(DataArray, Count * ElementSize);
DataArray := nil;
не претендую что откомпилируется без ошибок - я ж все-таки не компилятор :), но работать должно, причем надежно в обоих случаях.
Заводить отдельный класс мне кажется не нужно - так как будет тормозить и весьма сильно, а если скорости не требуется, то сойдет и SetLength - коротко и надежно.
Если же требуется еще большая скорость, то память надо выделять с указанием, что эта память не может быть свопирована и большую часть критических мест написать на asm-e, пользоваться целыми числами и без умножений-делений и т.д. но это уже совсем другая тема.
Smithson (2002-10-03 12:37:00) [2]Ну вы нагородили....
Le Taon (2002-10-03 12:31:00) [3]Mike Kouzmine
Твой подход может годиться только для
пользовательского кода самого верхнего уровня разового применения, набитого на живую нитку в режиме цейтнота.
(один мой знакомый называет его "живопырка").
Код ядра никогда так никогда не писался и писаться не будет,
вне зависимости от частоты процессора и объёмов памяти.
Игорь Шевченко (2002-10-03 11:39:00) [4]VAleksey © (03.10.02 11:24)
Эта...вопрос не так поставлен :-)
Я бы за его подход просто уволил бы :-)))
VAleksey (2002-10-03 11:30:00) [5]А чего вы спорите - то ?
По сути - то кажись все одинаково делают.
VAleksey (2002-10-03 11:24:00) [6]Добавлю потом дочитаю :)
2 Игорь Шевченко © (02.10.02 11:00)
А кто ему за это заплатит ?
Anatoly Podgoretsky (2002-10-03 09:46:00) [7]Kolya © (03.10.02 07:07)
Ты ничего не написал про применение, про время жизни массива, в зависимости от этого могут быть различные решения, но в если исходить из представленной информации, то у тебя два пути, или выделить сразу максимальное место, это при условии если известен максимально возможный размер массива, или выделять достаточно большими кусками, как ты и поступил, здесь опять два пути или наращивать фиксированнми кусками или интеллектуально, как TList, при изменении блока, размер увеличивается пропорционально размеру массива, но кратными какой то степени 2
Anatoly Podgoretsky (2002-10-03 09:38:00) [8]Vitalik © (02.10.02 15:41)
Для такого массиве a: array of array of integer), первое измерение является массивом указателей на массивы, поэтому можно написать
SetLength(a[5], 10);
SetLength(a[6], 20);
SetLength(a[7], 3);
Этоже не двухмерный массив, а массив массивов
KSergey (2002-10-03 09:33:00) [9]
> murza © (03.10.02 09:32)
> ДА.....БЛИН.
> Собрались программисты, то же мне.
> А хеширование, разреженные массивы - это как, немодные слова?
Так.. Еще раз для меня тупого... и Поподробнее...
murza (2002-10-03 09:32:00) [10]ДА.....БЛИН.
Собрались программисты, то же мне.
А хеширование, разреженные массивы - это как, немодные слова?
Kolya (2002-10-03 07:07:00) [11]Спасибо за советы! После каждой записи реаллокацию а делать не стал, а добавляю в массив 100 разделов вперед- Вроде все прекрасно работает.
А экономить память- это я привык с давних лет- обожаю пользовать байты вместо integer"ов, когда переменная не больше 256 :), что уж говорить про массивы
KSergey (2002-10-03 06:43:00) [12]
> Vitalik © (02.10.02 15:41)
> > KSergey
> А если у меня массив описан, например, так:
>
> a: array of array of integer;
>
> Setlength(a, 10);
> ... то когда я делаю следующее...
> SetLength(a[5], 10);
> ...то в памяти копируется весь массив a, или только a[5]?
Опа.... Хороший вопрос.. Я действительно не знаю как хранится массив в дельфи. В Си - знаю, а тут - нет.. В тех 2 книжках по D что у меня есть, этот вопрос не освещен (хотя странно; в любой книжке по Си эта тема обязательно разжевывается). А шибко лазить по хелпам - лень. Уж не взыщите.К стати, тема интересна, если чего нароете - будет интересно узнать.
> Mike Kouzmine (02.10.02 15:00)
> SetLength(Matrix,0);
> Если исключение происходит при увеличении массива, то он
> и не увеличится, что не скажешь про отдельный счетчик
Это интересно почему?! Деже если тупо написать
SetLength(a,100); // предположим, что тут произошло исключение
nASize := 100; // тогда эта строка ну никак не выполнится
Ну а уж в промышленном приложении при необходимости я точно обработаю исключения. Так что я не понимаю на чем основывается ваше утверждение.
> Th © (02.10.02 14:40)
> Что корректнее:
> SetLength(Matrix,0,0);[1]
> или
> Matrix:=nil;[2]
Не совсем понятно, чего вы хотите добиться: сказать, что массив теперь нулевой длины (случай 1) или освободить из под него память (случай 2)? Это вообще-то не одно и тоже. (Если кто-то несогласен - растолкую.) Так что решайте что вам надо в конкретном случае и действуйте сообразно обстоятельсвам.
И мне совершенно непонятна категоричность и однозначность, выраженная в ответе Mike Kouzmine (02.10.02 15:00)...
Mike Kouzmine (2002-10-02 17:46:00) [13]Это называется база данных. Ее не надо придумывать, а надо использовать или сервер или нативные форматы. Тем более в этом случае решены проблемы сортировки, поиска и прочие приблуды.
REA (2002-10-02 16:40:00) [14]На больших объемах лучше сначала узнать размер и потом не перераспределять часто - работает медленно. На малых можно и по 1 прибавлять.
Yegor Derevenets (2002-10-02 16:21:00) [15]Люди! А не проще ли написать какой-нибудь прямой объект или класс, выполняющий операции с массивом ов Long? Будет что-то вроде:
type
TLongArray=array of Long;
PLongArray=^TLongArray;
TArrayObject=object (TObject)
Data: PLongArray;
Count: Long;
constructor Create (aCount: Long);
procedure SetRange (aNewCount: Long);
procedure SetValue (aIndex, aValue: Long);
function GetValue (aIndex): Long;
destructor Destroy;
end;
В Create инициализировать Data, в SetRange выделять новый кусок из кучи, пихать в него все, что помещается, из старого и обновлять Data и Count. В SetValue если aIndex>=Count, то SetRange (aIndex+128); В GetValue тоже делать что-то наподобие.
Если кому надо - могу написать до конца. Вопщем, пишите на мыло!
P.S. Идея не нова - примерно так написаны коллекции в Object Pascal (потому и вмещали только 16380 элементов).
Vitalik (2002-10-02 15:41:00) [16]> KSergey
А если у меня массив описан, например, так:
a: array of array of integer;
Setlength(a, 10);
... то когда я делаю следующее...
SetLength(a[5], 10);
...то в памяти копируется весь массив a, или только a[5]?
Учитывая Вашу поправку ("Не спешите в меня плевать...") от (02.10.02 12:08), перефразирую вопрос:
В памяти массив a вместе со своими элементами-массивами (a[0]...a[n]) рассматривается как единое целое? Или сам массив а является массивом указателей, и значит изменение размеров его элементов не влияет на него самого?
Кстати, как вариант решения проблемы фрагментации памяти при изменения длинны массива, элементы которого имеют большие размеры, предлагаю пользоваться массивами указателей. Каждая ячейка такого массива весит 4 байта.
Th (2002-10-02 15:02:00) [17]THank"s
Mike Kouzmine (2002-10-02 15:00:00) [18]SetLength(Matrix,0);
Если исключение происходит при увеличении массива, то он и не увеличится, что не скажешь про отдельный счетчик
Th (2002-10-02 14:40:00) [19]Ребята, чем спорить, лучше ответьте мне на маленький вопрос ;))
Что корректнее:
SetLength(Matrix,0,0);
или
Matrix:=nil;
???
KSergey (2002-10-02 14:26:00) [20]Alex4444444444 (02.10.02 14:11)
Я правда не совсем понял, что вас возмущает... Вроде так у меня и написано после "основной" части. А то, что дельфи хватает куски по мегабайту - ну так в борланде же прекрасно понимают, что часто будут выделяться именно небольшие куски (под динамически создаваемые объекты, например) - вот они и пытаются описанную мною (не путать с мною придуманную!) методику сами использовать для уменьшения всяких проблем.
> Mike Kouzmine (02.10.02 13:12)
> "Не знаю как делает MBo, а я - элментарно: завожу переменную,
> в которой это все отслеживаю. (переменная жрет память? Так
> вроде байты мы перестали считать?)" - а если ошибка и не
> увеличился счетчик (любое исключение), да не одно? Универсальность
> и надежность подразумевает накладные расходы и надо это
> принимать или не принимать. Что вы и делаете (не принимаете).
Про надежность: а как вы думаете, как реализована ф-ция Length (ну или Hight)? А ведь в ней как раз и читается переменная, куда все записывается, только записывается силами VCL. Так что исключениям и она подвержена, значит и там точно такие же проблемы потенциально есть. А обработку исключений и я могу написать.
Хотя я конечно не буду спорить - где-то это вполне проходит, и я так делаю: надо в ф-ции массивчик небольшенький - да и фиг с ним, понаращиваю поэлементно, не страшно, все равно при выходе из ф-ции очищу. А вот когда приходится делать глобальный динамический массив в программе - вот тут я репу все же чешу и напрягаюсь. Может я и не прав...