Тем кто программировал в Basic, а затем перешел к Pascal, вероятно, доставляло неудобство отсутствие динамических массивов. Нет их и в ранних версиях Delphi , но ООП позволяет определить класс объектов, почти столь же удобных как и обычные массивы в Pascal, только динамических, т.е. таких, размер которых может изменяться в процессе работы программы. Вот объявление динамического массива целых:
Что мы хотим от такого массива? Во–первых, хорошо чтобы всегда получался 0 при чтении несуществующего элемента. Во–вторых, если число записывается за пределы массива, пусть массив расширяется до нужного размера и сохранят значение. Наконец, нужно уметь изменить размер массива явно.
Для явного задания начального размера массива в конструктор включён параметр N.
В конструкторе использована удобная функция работы с динамической памятью AllocMem. Она выделяет память нужного размера, заполняет ее нулями и возвращает указатель.
Этот метод возвращает значение элемента массива с заданными номером, если номер находится в пределах текущего размера массива. Если же номер указывает за пределы массива, то всегда возвращает 0.
Далее идёт наиболее нетривиальный метод SetE. Он записывает значение в заданный элемент массива, а если номер элемента лежит за пределами текущего размера, то предварительно расширяет массив.
Расширение массива — трудоемкая операция. В SetE, чтобы массив работал эффективно, применены два характерных приема оптимизации таких действий. Основные затраты при изменении текущего размера связаны с обращением к системе за дополнительной памятью и с копированием текущего массива на новое место. Чтобы сократить количество обращений, используется “страничное выделение памяти”.
Из практики замечено, что если понадобился массив больше существующего на один элемент, весьма вероятно, что понадобится увеличить его и на два и на три. В этом случае, целесообразно при первом же обращении увеличить размер массива сразу на целый блок — страницу. Это и есть первый прием, позволяющий сократить количество обращений к системе в несколько раз. В нашем примере размер страницы определен константой Q и равен 16.
Второй прием связан с функцией ReAllocMem. Это системная утилита, позволяющая эффективно изменять текущий размер блока памяти. Если возможно, она стремиться увеличить блок без перемещения, просто добавив в конец необходимое количество памяти. Только если память в конце блока занята другими данными, функция выделяет память в другом месте, копирует содержимое массива на новое место, освобождает прежний блок памяти и возвращает указатель на новое место. Таким образом, количество копирований массива существенно сокращается по сравнению с грубой схемой, в которой оно выполняется каждый раз.
Ещё одна маленькая хитрость состоит в том, что массив расширяется только для запоминания ненулевых значений. Ведь при чтении ноль получится даже для отсутствующих элементов.
Следующий метод Resize помогает пользователю нашего класса ещё больше повысить эффективность. Если размер массива выяснился в ходе работы программы, тогда, задав его явно, программист получит объект по быстродействию мало отличающийся от обычного статического массива.
Как видно из деструктора, ReAllocMem позволяет не только получать, но и освобождать выделенную память. Вот пример работы с объектом нашего класса:
Обратите внимание, что синтаксически использование нашего массива очень сходно с обычным. Этой наглядности помогло добиться свойство Vect принятое по умолчанию.
Опубликовал Kest
June 21 2011 13:37:35 ·
0 Комментариев ·
11248 Прочтений ·
• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •
Комментарии
Нет комментариев.
Добавить комментарий
Рейтинги
Рейтинг доступен только для пользователей.
Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.
Нет данных для оценки.
Гость
Вы не зарегистрированны? Нажмите здесь для регистрации.