Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 13.07.2008, 10:32   #1
Dogmat
Пользователь
 
Регистрация: 12.06.2008
Сообщений: 76
По умолчанию Удаление элемента динамического массива

Уважаемые форумчане, поясните в чем может заключаться проблема.

Суть: имеем динамический массив типа record с соответствующими полями. На данном этапе существует лишь создание, добавление, удаление и перемещение по ячейкам массива, сопровождающееся выводом информации из текужей ячейки массива. В дальнейшем будет что-то большее. При создании все поля ячеек заполняются рандомно. Удаление работает нормаьно при удалении с конца массива, с любой другой позицией проблема. Само удаление протекает казалось бы нормально, но в дальнейшем при перемещении по массиву или созданию новой ячейки программа ругается, рылся в Internet-е нашёл удаление полностью идентичное моему, пишут, что универсальное и должно работать.

Теперь часть кода [процедура удаления элемента]:
Pos - позиция в массиве, реальная позиция, тобишь если 10 элементов то последняя позиция = 9...
Count - кол-во, аналогично Pos, реальное кол-во...
mPoP сам массив (mPoP: array of character, где character=record с определенными полями)

if pos=High(mPoP) then SetLength(mPoP,Count) // в случае если удаляем элемент массива, стоящий на последней позиции, т.к. SetLength требует указать кол-во элементов то Count с учётом нуля как раз является на 1 меньше чем размер массива, поэтому в качестве параментра просто Count, здесь всё работает
else
begin
move(mPoP[Pos+1], mPoP[Pos], (Count-Pos)*sizeof(mPoP[Pos]));
SetLength(mPoP,Count);
// вот здесь, как я понял трабла, тобишь сдвигаем просто на один элемент и далее, чтобы освободить память просто переопределяем размер массива, материться здесь не матерится, но в дальнейшем при перемещении или добавлении... возможно и удалении начинает ругаться, причем ругается на совершенно разные вещи, к примеру в строках где идет обращение к компонентам формы, функции для вывода и генерации элементов массива точно работают, я перепроверил уже несколько раз, суть в том что если не переопределять размер (тоесть без SetLength(mPoP,Count)), а просто сдвигать элементы затерая ненужные всё будет работать и не ругаться, но тогда массив будет оставаться того же размера, что не желательно.
end;
dec(Count);
if Pos<>0 then dec(Pos);
If Count>=0 then Show
else
begin
Label_CurrentPosition.Caption:='0/0';
Label_Name.Caption:='';
MemoInformation.Clear;
Image.Picture:=nil;
Button_Kill.Enabled:=False;
Button_Next.Enabled:=False;
Button_Previous.Enabled:=False;
end
// ну а здесь просто уменьшение Pos, Count и вывод инфы в зависимости от случая, Show - самопальная функция вывода инфы на компоненты...

Уверен, что трабла именно в этом месте...
Подскажите пожалуйста, может кто-то сталкивался с похожей проблемой, или быть может более лучший способ работы с динамическими массивами без использования SetLength, High, Low и т.д. буду благодарен...
Dogmat вне форума Ответить с цитированием
Старый 13.07.2008, 12:51   #2
Greblin
Меркантильный кю
Участник клуба
 
Аватар для Greblin
 
Регистрация: 02.02.2008
Сообщений: 1,001
По умолчанию

Слушай, может я чего-то не понимаю в этой жизни, но у тебя же вот здесь
Код:
move(mPoP[Pos+1], mPoP[Pos], (Count-Pos)*sizeof(mPoP[Pos]));
SetLength(mPoP,Count);
размер массива как был Count, так и остался Count
Росли вроде умными, выросли дурнями... (c)А.Васильев
Greblin вне форума Ответить с цитированием
Старый 13.07.2008, 13:16   #3
Dogmat
Пользователь
 
Регистрация: 12.06.2008
Сообщений: 76
По умолчанию

Цитата:
Сообщение от Greblin Посмотреть сообщение
Слушай, может я чего-то не понимаю в этой жизни, но у тебя же вот здесь
Код:
move(mPoP[Pos+1], mPoP[Pos], (Count-Pos)*sizeof(mPoP[Pos]));
SetLength(mPoP,Count);
размер массива как был Count, так и остался Count

Допустим я ввожу
Count:=7
SetLength(mPoP, Count)
при этом получается массив с ячейками 0..6, вот...
затем после этой процедуры я dec(Count) мне так удобней в дальнейшем работать, тоесть Count теперь хранит номер последней ячейки массива тоесть 6
поэтому если я удаляю один элемент я уже пишу просто SetLength(mPoP, Count) где Count равен уже 6... тем самым на 1 меньше...
трабла не в этом, читайте первое сообщение... пожалуйста... по логике всё вроде должно работать... потому и обращаюсь... если с конца удалять то всё работает, если из середины юзая Move то траблы в итоге...
Dogmat вне форума Ответить с цитированием
Старый 13.07.2008, 13:29   #4
alexBlack
Участник клуба
 
Регистрация: 12.10.2007
Сообщений: 1,204
По умолчанию

Меня несколько смущает использование move для динамических массивов:
move(mPoP[Pos+1], mPoP[Pos], (Count-Pos)*sizeof(mPoP[Pos]));

Сейчас попробую объяснить.

В system.pas есть функция _DynArrayCopy.
Ее компилятор использует для копирования содержания динамических массивов. Внутри есть комментарий и код для копирования:

Код:
// If the element type needs destruction, we must copy each element,
// otherwise we can just copy the bits
// If the element type needs destruction, we must copy each element,
// otherwise we can just copy the bits
 if count > 0 then begin
    if typeInf <> nil then begin
       FillChar(p^, count*elSize, 0);
       CopyArray(p, a, typeInf, count)
    end else
       Move(a^, p^, count*elSize);
 end;
Как видите, для элементов, у которых требуется finalize() (для них можно вызвать typeInfo), копирование производится поэлементно.

Вернемся к нашим record. Пока в них нет String, move можно смело
применять. Как только в record добавляется поле типа String, запись требует вызова finalize() когда количество ссылок на нее станет равным равным 0. Вот здесь и начинаются проблемы.

Посмотрим еще раз на move и возьмем простейший пример - удаление нулевого элемента массима длиной 10:

move(A[1], A[0], 9*sizeOf(A[1]);
setLength(A, 9);

Во-первых затирается 0-й элемент, а вызова finalize для него не делается. Это утечка памяти.

Во-вторых, что еще хуже, после move последний элемент (9-й) повторен дважды (на 8-й и на 9-й позиции), а addRef для него не сделано. После SetLength последний элемент будет отрезан и для него будет вызвана finalize, а ссылка на него останется (в 8-й позиции). Причем это не приведет к проблемам сразу, а только когда компилятор выделит память для другого объекта.

Выводы.
Не применяйте move для массивов, содержащий элементы, которые требуют finalize(). Используйте обычное копирование.
alexBlack вне форума Ответить с цитированием
Старый 13.07.2008, 13:51   #5
Dogmat
Пользователь
 
Регистрация: 12.06.2008
Сообщений: 76
По умолчанию

Тогда еще вопрос, этот способ подразумевает использование еще одного динамического массива и копирование элементов одного массива в другой каждый раз при удалении очередного элемента? Если так, тогда как это влияет на время выполнения... как я понимаю массив содержит ссылки на адреса памяти, тогда по сути не сильно влияет? И еще, разве можно использовать finalize() непосредственно к элементу массива, или имеется ввиду к string-у? честно не работал почти с динамическими...

P.s. кстати, да record в моём случае содержит парочку string-ов...
и спасибо за совет в любом случае, попробую разобраться и сделать.
Dogmat вне форума Ответить с цитированием
Старый 13.07.2008, 14:02   #6
alexBlack
Участник клуба
 
Регистрация: 12.10.2007
Сообщений: 1,204
По умолчанию

Цитата:
Сообщение от Dogmat Посмотреть сообщение
Тогда еще вопрос, этот способ подразумевает использование еще одного динамического массива и копирование элементов одного массива в другой каждый раз при удалении очередного элемента? Если так, тогда как это влияет на время выполнения... как я понимаю массив содержит ссылки на адреса памяти, тогда по сути не сильно влияет?
Не подразумевает использование еще одного массива.

for i:=1 to 9 do A[i-1] := A[i]; // вместо move

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

Цитата:
И еще, разве можно использовать finalize() непосредственно к элементу массива, или имеется ввиду к string-у? честно не работал почти с динамическими...
Да, можно делать finalize(A[0]). Компилятор сам разберется, как его применять. Но есть одно но. Когда record не требует finalize, на этот вызов компилятор даст предупреждение.

Лучше не вмешиваться. То есть или мы сами распределяем и освобождаем память или отдаем это компилятору.
alexBlack вне форума Ответить с цитированием
Старый 13.07.2008, 14:33   #7
Dogmat
Пользователь
 
Регистрация: 12.06.2008
Сообщений: 76
По умолчанию

Спасибо большое, теперь понял, всё оказалось проще простого) как обычно всё простое гениальн... уже проверил, работает... просто вычетал пример с использованием move, про строки ни слова не было написано, не думал что можно будет вот так просто прогнать да и показалось что move быстрее всё сделает, потому и использовал.

Думаю этот вопрос закрыт, всем спасибо за выделенное время...
Dogmat вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Удаление записи из динамического масива... Altera Общие вопросы Delphi 4 09.06.2008 09:15
Удаление элемента массива chiffa Общие вопросы Delphi 1 03.01.2008 19:24
Поиск позиции элемента несортированного массива gdneon Microsoft Office Excel 4 16.04.2007 08:08