|
|
Регистрация Восстановить пароль |
Повторная активизация e-mail |
Регистрация | Задать вопрос |
Заплачу за решение |
Новые сообщения |
Сообщения за день |
Расширенный поиск |
Правила |
Всё прочитано |
|
Опции темы | Поиск в этой теме |
13.07.2008, 10:32 | #1 |
Пользователь
Регистрация: 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 и т.д. буду благодарен... |
13.07.2008, 12:51 | #2 |
Меркантильный кю
Участник клуба
Регистрация: 02.02.2008
Сообщений: 1,001
|
Слушай, может я чего-то не понимаю в этой жизни, но у тебя же вот здесь
Код:
Росли вроде умными, выросли дурнями... (c)А.Васильев
|
13.07.2008, 13:16 | #3 | |
Пользователь
Регистрация: 12.06.2008
Сообщений: 76
|
Цитата:
Допустим я ввожу Count:=7 SetLength(mPoP, Count) при этом получается массив с ячейками 0..6, вот... затем после этой процедуры я dec(Count) мне так удобней в дальнейшем работать, тоесть Count теперь хранит номер последней ячейки массива тоесть 6 поэтому если я удаляю один элемент я уже пишу просто SetLength(mPoP, Count) где Count равен уже 6... тем самым на 1 меньше... трабла не в этом, читайте первое сообщение... пожалуйста... по логике всё вроде должно работать... потому и обращаюсь... если с конца удалять то всё работает, если из середины юзая Move то траблы в итоге... |
|
13.07.2008, 13:29 | #4 |
Участник клуба
Регистрация: 12.10.2007
Сообщений: 1,204
|
Меня несколько смущает использование move для динамических массивов:
move(mPoP[Pos+1], mPoP[Pos], (Count-Pos)*sizeof(mPoP[Pos])); Сейчас попробую объяснить. В system.pas есть функция _DynArrayCopy. Ее компилятор использует для копирования содержания динамических массивов. Внутри есть комментарий и код для копирования: Код:
Вернемся к нашим 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(). Используйте обычное копирование. |
13.07.2008, 13:51 | #5 |
Пользователь
Регистрация: 12.06.2008
Сообщений: 76
|
Тогда еще вопрос, этот способ подразумевает использование еще одного динамического массива и копирование элементов одного массива в другой каждый раз при удалении очередного элемента? Если так, тогда как это влияет на время выполнения... как я понимаю массив содержит ссылки на адреса памяти, тогда по сути не сильно влияет? И еще, разве можно использовать finalize() непосредственно к элементу массива, или имеется ввиду к string-у? честно не работал почти с динамическими...
P.s. кстати, да record в моём случае содержит парочку string-ов... и спасибо за совет в любом случае, попробую разобраться и сделать. |
13.07.2008, 14:02 | #6 | ||
Участник клуба
Регистрация: 12.10.2007
Сообщений: 1,204
|
Цитата:
for i:=1 to 9 do A[i-1] := A[i]; // вместо move В этом случае компилятор поймет, что копируется запись, содержащая строку, и в нужных местах подставит addRef/finalize. Цитата:
Лучше не вмешиваться. То есть или мы сами распределяем и освобождаем память или отдаем это компилятору. |
||
13.07.2008, 14:33 | #7 |
Пользователь
Регистрация: 12.06.2008
Сообщений: 76
|
Спасибо большое, теперь понял, всё оказалось проще простого) как обычно всё простое гениальн... уже проверил, работает... просто вычетал пример с использованием move, про строки ни слова не было написано, не думал что можно будет вот так просто прогнать да и показалось что move быстрее всё сделает, потому и использовал.
Думаю этот вопрос закрыт, всем спасибо за выделенное время... |
Похожие темы | ||||
Тема | Автор | Раздел | Ответов | Последнее сообщение |
Удаление записи из динамического масива... | 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 |