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

Вниз

Можно ли удалить элемент динамического массива?   Найти похожие ветки 

 
Sagrer   (2005-07-05 17:42) [0]

Пытаюсь что-то сделать с помощью CopyRange но не получается... ведь если надо удалять элемент в середине массива - то я думал делать так чтобы часть до этого элемента оставалась неизменной а в часть начиная с этого элемента скопировать содержимое массива начиная с №удаляемого элемента + 1.

Но результат копирования не удается присоединить к уже существующему массиву, только как бы создавая новый массив, начинающийся с 1-го копируемого элемента :(.

Пытался писать на адрес этого элемента - но ссылка получается на то на что ссылается элемент (сами элементы - ссылки на объекты класса).

вот так вот :(. Пока ничего умнее чем писать копирование для содержимого того на что ссылаются элементы не придумал :(.


 
Fay ©   (2005-07-05 17:52) [1]

Ничего не понял. Совсем.
Что требуется и почему нельзя
MyArray[n] := MyArray[High(MyArray)];
SelLength(MyArray, High(MyArray));

?


 
Юрий Зотов ©   (2005-07-05 19:10) [2]

Sagrer   (05.07.05 17:42)

Если задача допускает переупорядочение элементов массива - см. [1]. Если не допускает - CopyMemory и SetLength.


 
begin...end ©   (2005-07-05 19:17) [3]

> Юрий Зотов ©   (05.07.05 19:10) [2]
> Если не допускает - CopyMemory и SetLength.

Добавлю, что для случая, когда тип элементов массива является типом с управляемым временем жизни, поэлементное присваивание Element[I] := Element[I + 1] может быть безопаснее, чем CopyMemory.


 
Fay ©   (2005-07-05 19:24) [4]

2 Sagrer   (05.07.05 17:42)
Короче, бери TList и не парь мозги 8)


 
Юрий Зотов ©   (2005-07-05 20:10) [5]

> begin...end ©   (05.07.05 19:17) [3]

Э-э-э... а каким же образом?


 
begin...end ©   (2005-07-05 20:37) [6]

> Юрий Зотов ©   (05.07.05 20:10) [5]

При удалении из динамического массива одного такого элемента (например, типа String) путём копирования блока элементов с помощью CopyMemory один элемент окажется в массиве в двух экземплярах (один экземпляр -- в самом конце массива, другой -- предпоследний). Эти экземпляры -- указатели на одну и ту же область памяти, содержащую управляющую структуру и тело строки. Если теперь сократить длину массива на единицу (используя SetLength), последний элемент (если его счётчик ссылок был равен 1) будет автоматически финализирован (видно, что из DynArraySetLength вызывается _FinalizeArray, а из неё -- _LStrClr). Это означает, что память, занимаемая телом строки, освободится, и последний элемент нового, усечённого, массива тоже станет недействительным указателем (потому что он продолжает указывать туда, куда указывал только что финализированный элемент).

Если же применить поэлементное присваивание, то счётчик ссылок предпоследнего элемента будет на единицу больше (он увеличится при присваивании), и такой ситуации не возникнет.


 
begin...end ©   (2005-07-05 20:59) [7]

> Юрий Зотов ©   (05.07.05 20:10) [5]

Вот простой пример, подтверждающий [3] и [6]:

var
 A: array of string;

procedure TForm1.Button1Click(Sender: TObject);
var
 I: Integer;
begin
 SetLength(A, 10);
 for I := Low(A) to High(A) do
   A[I] := "ABC";
 // "Удаляем" нулевой элемент
 CopyMemory(@A[0], @A[1], 9 * sizeof(A[0]));
 SetLength(A, Pred(Length(A)))
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 ShowMessage(A[8])
end.


Нажимаем сначала Button1, затем -- Button2. Получаем AV.
Если же строку с CopyMemory заменить на for I := 0 to 8 do A[I] := A[I + 1], то всё нормально.


 
Юрий Зотов ©   (2005-07-05 23:35) [8]

> begin...end ©   (05.07.05 20:59) [7]

Точно, есть такая штука. Но тогда, видимо, лучше будет сочетать оба способа - CopyMemory для всех элементов, кроме последнего, а последний присвоить предпоследнему и удалить.


 
Alex Konshin ©   (2005-07-06 00:53) [9]

Эффективнее сначала финализировать удаляемый элемент (явно или косвенно), потом копировать память куском (чем - выбирайте по вкусу), потом обнулять последний элемент и уж после этого SetLength.


 
evvcom ©   (2005-07-06 10:14) [10]


> последний присвоить предпоследнему

Тогда тот же эффект, описанный в [6], может проявиться для "предпоследнего" элемента. Если уж начали использовать CopyMemory или Move, то делать как в [9]. Уточню фразу (не для мастеров естественно)

> обнулять последний элемент

для последнего элемента выполнить FillChar(X[i], SizeOf(<элемент массива>), 0);


 
REA   (2005-07-06 10:38) [11]

А тот, который удаляется не надо вручную финализировать?


 
begin...end ©   (2005-07-06 10:41) [12]

> REA   (06.07.05 10:38) [11]

Надо.


 
evvcom ©   (2005-07-06 10:43) [13]


> А тот, который удаляется не надо вручную финализировать?

Ответили же в [9]:

> сначала финализировать удаляемый элемент (явно или косвенно),


 
msguns ©   (2005-07-06 10:43) [14]

И все же объясните, пожалуйста, почему для хранения кол-ва объектов, которое часто меняется (объекты удаляются и добавляются) не использовать TList вместо массива и типизированные указатели.


 
Alex Konshin ©   (2005-07-06 12:00) [15]

При мелких объектах TList получается неэффективным, так как для каждого элемента нужно отводить память, что есть лишний вызов менеджера памяти, а при многопоточности еще и в нем включаются блокировки.
Частичным выходом может быть свой менеджер памяти, но тогда у объектов NewInstance должен быть перекрыт.

А у меня свои массивы для этого дела есть. По сути это совмещение и того, и другого. Смотрите Arrays на моем сайте. Заодно там есть базовые классы для массивов со встроенной индексацией (быстрый поиск) и сортировкой, но они достаются уже не бесплатно - размер элемента массива возрастает.


 
msguns ©   (2005-07-06 12:42) [16]

>Alex Konshin ©   (06.07.05 12:00) [15]

Однако, если объектами является, например, множеством записей типа букмарок (например, для хранения выделенных юзером записей датасета, отображаемого в гриде), считываемых из БД, то, ИМХО, проще все же использовать TList. Хотя бы потому, что позволяет хранить ссылки на сложные объекты-контейнеры (например, рекорды). Даже большое кол-во таких "пометок", ИМХО, не приведет к замедлению программы, зато код зделает внятным и прозрачным. Да и сортировать списки проще, чем массивы (побейте, если неправ)


 
Alex Konshin ©   (2005-07-06 13:06) [17]

Как раз-таки в случае с record проще не использовать TList, потому что придется явно выделять-освобождать каждый элемент. Вот для объектов это можно частично автоматизировать освобождение с помощью TObjectList.

У меня массивы сами сортируются, причем это не значит, что данные в нем перемещаются. Там просто есть понятие логического и физического индекса элемента и есть логическая переадресация, вот она-то и может быть отсортирована (или отфильрована). По сути, это почти готовая таблица данных в памяти.


 
msguns ©   (2005-07-06 13:34) [18]

>Alex Konshin ©   (06.07.05 13:06) [17]
>У меня массивы сами сортируются, причем это не значит, что данные в нем перемещаются

Ну єто понятно. Но ведь не все располагают подобными "массивами". Все же любопытно сравнивать стандартные массивы и списки. Вы против списков, как я понял, в описанном мною случае. Тогда вопрос: сколько мне надо резервировать памяти под массив букмарок (имеются в виду не TBookMark, а собственные объекти, содержащие всю необходимую информацию об отмеченных записях) изначально, когда датасет просто окрывается и юзер еще ничего не выделил ? Если нисколько, то при каждой отметке у меня будет итти запрос к менеджеру памяти точно также, как при добавлении в список. В чем разница-то ? Зато при удалении мне надо заниматься переформировыванием (копированием в цикле) всего массива, в то время как в списках этого не требуется. Я уже не говорю про сортировки и т.д. Т.е. налицо отсутствие "экономии" на выделение памяти и присутствие лишних кусков кода, занимающихся "инспектированием" массива.
Или я неправ ?


 
Alex Konshin ©   (2005-07-07 03:18) [19]

Давайте для начала отделим мух от котлет.
Объекты класса TList и списки - это очень разные вещи. Не надо их так называть, это создает путаницу.

При добавлении некого объекта к объекту TList мы имеем:
1. Одно обращение GetMem для выделения памяти под этот самый объект.
2. Возможно обращение к менеджеру памяти из самого TList, когда ноый Size<Capacity. То есть, это достаточно редко, но, правда, это может привести к копированию всего массива ссылок на новое место.

В случае массива мы имеем только второе. Но к сожалению (или к счастью) в Delphi нет возможности создания объекта в массиве, все так называемые массивы объектов реально являются массивами ссылок на объекты. Как следствие эти массивы объектов действительно почти не отличаются от TList/TObjectList.
С точки зрения обращений к менеджеру памяти разницы между массивами объектов и TList/TObjectList практически нет. Но для массивов записей разница существенна, т.к. сама запись располагается в самом массиве. Преимущество это или недостаток? Смотря для чего. Удалять, конечно, хуже - больше копировать (обычно). Добавлять же может оказаться быстрее, но до тех пор, пока не превысим Capacity, тогда придется опять-таки копировать больше. Нужно еще учитывать, что цена обращения к менеджеру памяти разная для однопоточных и мультипоточных приложений.

В моих массивах как раз-таки и реализованы реальные массивы объектов. То есть, у меня сам объект сидит в массиве. Но при этом вставки-удаления-сортировки для некоторых типов массивов (у меня там несколько базовых классов) не приводят к перемещению данных внутри массива, т.к. есть переадресация.


 
Alex Konshin ©   (2005-07-07 04:48) [20]

Замеченые очепятки:
Возможно обращение к менеджеру памяти из самого TList, когда ноый Size<Capacity.
Возможно обращение к менеджеру памяти из самого TList, когда новый Size>Capacity.


 
Barsuk   (2005-07-07 15:43) [21]

Удалено модератором
Примечание: Задай вопрос в своей ветке


 
evvcom ©   (2005-07-07 16:03) [22]

Кликни с Ctrl по M в M[x], а действительно ли это тот DynArray? Потом также кликни по DynArray, а действительно ли это тот array of integer? Глядишь чего-нить и прояснится.


 
Barsuk   (2005-07-07 17:13) [23]

Удалено модератором


 
Alex Konshin ©   (2005-07-08 02:23) [24]

Создай свою тему и задавай там свой вопрос.


 
ЮЮ ©   (2005-07-08 03:09) [25]

>  ..... // здесь
ошибка в том, что ........ :)



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

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

Наверх





Память: 0.52 MB
Время: 0.019 c
14-1119961936
ANB
2005-06-28 16:32
2005.07.25
Какая гадость эта заливная рыба


4-1117110559
DimN
2005-05-26 16:29
2005.07.25
Узнать цвет точки на экране


14-1120069581
SpyBoy
2005-06-29 22:26
2005.07.25
Without dll :)


14-1119716063
Soft
2005-06-25 20:14
2005.07.25
Радиолюбителям.


3-1118777780
snaip
2005-06-14 23:36
2005.07.25
DBNavigator(работа с БД)





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