Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпоры по ООП.doc
Скачиваний:
31
Добавлен:
25.09.2019
Размер:
1.04 Mб
Скачать

78.Контейнер объектов Array

Весьма полезеный класс-контейнер: массив, который можно использовать в качестве передаваемых значений. Подсчет количества ссылок дает возможность вытворять такие вещи с минимальными затратами:

Array<String> EnumerateSomething();

void UseThisList(List<int> list);

Поясню: при передаче контейнера в качестве аргумента или возвращаемого значения поэлементного копирования не происходит; у объекта только увеличивается/уменьшается внутренний счетчик ссылок. В принципе, "классика жанра", отлично разжеванная у Саттера: используется Copy-On-Write. Иными словами, при изменении массива (а именно — хотя бы одного из его элементов) создается полностью независимая его копия, с которой в дальнейшем производятся необходимые действия.

Это реализуется внутри методов контейнеров:

void Array<T>::SetAt(int index, const T& newValue)

{

CopyOnWrite();

//... работаем с независимой копией

}

bool Array<T>::IsEmpty() const

{

//... метод константный - массив не изменяется, CopyOnWrite не нужен.

}

Подобным же образом реализованы большинство известных String-классов в различных библиотеках: ATL/WTL, MFC, VCL.

Элементы Array располагаются в памяти непрерывно. Сначала следует заголовок, включающий счетчик ссылок, текущее количество элементов и емкость контейнера (зарезервированный размер). Сам по себе Array является лишь указателем на выделенную область памяти (в частности, на 0-й элемент, т.е. на область памяти сразу после заголовка), поэтому размер переменной типа Array всегда равен размеру указателя, что идеально подходит для передачи значений в/из функций.

Преимущества Array:

Высокая скорость работы

Минимальные требования к типу элементов: наличие доступных конструктора копирования и деструктора

Возможность добавления новых элементов в конец массива

Независимость от Runtime library

Кроссплатформенность

Гарантированная целостность при возникновении исключений (exception-safe)

Недостатки Array:

Отсутствие поддержки STL-итераторов. В перспективе можно добавить пару begin()/end(), возвращающие const_iterator

Не хватает методов для удаления отдельных элементов, вставки в середину последовательности и т.п.

Одним из фундаментальных компонентов STL являются итераторы. Итераторы - удобная обертка для указателей, а выполнены они как шаблоны классов. Кстати говоря, обычный указатель тоже можно считать итератором, правда, очень примитивным. Итераторы обладают массой достоинств, например таких, как автоматическое отслеживание размера типа, на который указывает итератор, или автоматизированные операции инкремента и декремента для перехода от элемента к элементу. Именно благодаря этим возможностям итераторы и являются фундаментом всей библиотеки.

Итераторы можно условно разделить на две категории: основные и вспомогательные. Но прежде чем перейти к подробному описанию и тех и других, остановимся на двух важных правилах работы с итераторами: получения итераторов и отслеживания значения "за пределом". Многие функции и методы классов STL возвращают итераторы, вместо того чтобы производить действия над обычными указателями Си++.

Основные итераторы

Основные итераторы используются наиболее часто. И вы будете сталкиваться с ними постоянно. Поэтому с их рассмотрения мы и начнем.

Основные итераторы взаимозаменяемы. Однако при этом нужно соблюдать иерархию старшинства (рис. 1).