Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Язык программирования C++. Пятое издание - Стенли Липпман

Язык программирования C++. Пятое издание - Стенли Липпман

Читать онлайн Язык программирования C++. Пятое издание - Стенли Липпман

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 110 111 112 113 114 115 116 117 118 ... 297
Перейти на страницу:

Фиксированный характер размера массивов влияет также на поведение остальных конструкторов, действительно определяющих массив. В отличие от других контейнеров, созданный по умолчанию массив не пуст: количество его элементов соответствует размеру, а инициализированы они значением по умолчанию (см. раздел 2.2.1), как и элементы встроенного массива (см. раздел 3.5.1). При списочной инициализации массива количество инициализаторов не должно превышать размер массива. Если инициализаторов меньше, чем элементов массива, они используются для первых элементов, а все остальные инициализируются значением по умолчанию (см. раздел 3.3.1). В любом случае, если типом элемента является класс, то у него должен быть стандартный конструктор, обеспечивающий инициализацию значением по умолчанию:

array<int, 10> ia1;        // десять целых чисел, инициализированных

                           // значением по умолчанию

array<int, 10> ia2 = {0,1,2,3,4,5,6,7,8,9}; // списочная инициализация

array<int, 10> ia3 = {42}; // ia3[0] содержит значение 42, остальные

                           // элементы - значение 0

Следует заметить, что хоть и нельзя копировать или присваивать объекты массивов встроенных типов (см. раздел 3.5.1), для контейнеров array такого ограничения нет:

int digs[10] = {0,1,2,3,4,5,6,7,8,9};

int cpy[10] = digs; // ошибка: встроенные массивы не допускают

                    // копирования и присвоения

array<int, 10> digits = {0,1,2,3,4,5,6,7,8,9};

array<int, 10> copy = digits; // ok: если типы массивов совпадают

Как обычно, инициализирующий контейнер должен иметь тот же тип, что и создаваемый. Для контейнера array совпадать должны тип элемента и размер, поскольку размер массива — часть его типа.

Упражнения раздела 9.2.4

Упражнение 9.11. Приведите пример каждого из шести способов создания и инициализации контейнеров vector. Объясните, какие значения будет содержать каждый вектор.

Упражнение 9.12. Объясните различие между конструктором, получающим контейнер для копирования, и конструктором получающим два итератора.

Упражнение 9.13. Как инициализировать контейнер vector<double> из контейнера list<int> и контейнера vector<int>? Напишите код для проверки ответов.

9.2.5. Присвоение и функция swap()

Связанные с присвоением операторы, перечисленные в табл. 9.4, воздействуют на весь контейнер. Оператор присвоения заменяет весь диапазон элементов в левом контейнере копиями элементов из правого:

c1 = c2;      // заменяет содержимое контейнера c1 копией

              // элементов контейнера c2

c1 = {a,b,c}; // после присвоения контейнер c1 имеет размер 3

После первого присвоения контейнеры слева и справа равны. Если контейнеры имели неравный размер, после присвоения у обоих будет размер контейнера из правого операнда. После второго присвоения размер контейнера c1 составит 3, что соответствует количеству значений, представленных в списке.

Таблица 9.4. Операторы присвоения контейнеров

c1 = c2 Заменяет элементы контейнера c1 копиями элементов контейнера c2. Контейнеры c1 и c2 должны иметь тот же тип с = {a, b, с...} Заменяет элементы контейнера c1 копиями элементов списка инициализации. (Недопустимо для массива.) swap(c1, c2) c1.swap(c2) Обменивает элементы контейнеров c1 и c2. Контейнеры c1 и c2 должны иметь тот же тип. Обычно функция swap() выполняется намного быстрее, чем процесс копирования элементов из контейнера c2 в c1 Операторы присвоения недопустимы для ассоциативных контейнеров и массива seq.assign(b,е) Заменяет элементы в контейнере seq таковыми из диапазона, обозначенного итераторами b и е. Итераторы b и е не должны ссылаться на элементы в контейнере seq seq.assign(il) Заменяет элементы в контейнере seq таковыми из списка инициализации il seq.assign(n,t) Заменяет элементы в контейнере seq набором из n элементов со значением t

В отличие от встроенных массивов, библиотечный тип array поддерживает присвоение. У левых и правых операндов должен быть одинаковый тип:

array<int, 10> a1 = {0,1,2,3,4,5,6,7,8,9};

array<int, 10> а2 = {0}; // все элементы со значением 0

a1 = а2;  // замена элементов в a1

а2 = {0}; // ошибка: нельзя присвоить массиву значения из списка

Поскольку размер правого операнда может отличаться от размера левого операнда, тип array не поддерживает функцию assign() и это не позволяет присваивать значения из списка.

Связанные с присвоением операторы делают недопустимыми итераторы, ссылки и указатели на контейнер слева.

Применение функции assign() (только последовательные контейнеры)

Оператор присвоения требует совпадения типов левых и правых операндов. Он копирует все элементы правого операнда в левый. Последовательные контейнеры (кроме array) определяют также функцию-член assign(), обеспечивающую присвоение разных, но совместимых типов, или присвоение контейнерам последовательностей. Функция assign() заменяет все элементы в левом контейнере копиями элементов, указанных в ее аргументе. Например, функцию assign() можно использовать для присвоения диапазона значений char* из вектора в список строк:

list<string> names;

vector<const char*> oldstyle;

names = oldstyle; // ошибка: типы контейнеров не совпадают

// ok: преобразование из const char* в string возможно

names.assign(oldstyle.cbegin(), oldstyle.cend());

Вызов функции assign() заменяет элементы в контейнере names копиями элементов из диапазона, обозначенного итераторами. Аргументы функции assign() определяют количество элементов контейнера и их значения.

Поскольку существующие элементы заменяются, итераторы, переданные функции assign(), не должны относиться к контейнеру, для которого вызвана функция assign().

Вторая версия функции assign() получает целочисленное значение и значение элемента. Она заменяет указанное количество элементов контейнера заданным значением:

// эквивалент slist1.clear();

// сопровождается slist1.insert(slist1.begin(), 10, "Hiya!");

list<string> slist1(1);     // один элемент; пустая строка

slist1.assign(10, "Hiya!"); // десять элементов; со значением "Hiya!"

Применение функции swap()

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

vector<string> svec1(10); // вектор из 10 элементов

vector<string> svec2(24); // вектор из 24 элементов

svec1.swap(svec2);

После выполнения функции swap() вектор svec1 содержит 24 строки, а вектор svec2 — 10. За исключением массивов смена двух контейнеров осуществляется очень быстро — сами элементы не меняются; меняются лишь внутренние структуры данных.

За исключением массивов функция swap() не копирует, не удаляет и не вставляет элементы, поэтому она гарантированно выполняется за постоянное время.

Благодаря тому факту, что элементы не перемещаются, итераторы, ссылки и указатели в контейнере, за исключением контейнера string, остаются допустимыми. Они продолжают указывать на те же элементы, что и перед перестановкой. Однако после вызова функции swap() эти элементы находятся в другом контейнере. Предположим, например, что итератор iter обозначал в векторе строк позицию svec1[3]. После вызова функции swap() он обозначит элемент в позиции svec2[3]. В отличие от других контейнеров, вызов функции swap() для строки делает некорректными итераторы, ссылки и указатели.

1 ... 110 111 112 113 114 115 116 117 118 ... 297
Перейти на страницу:
На этой странице вы можете бесплатно скачать Язык программирования C++. Пятое издание - Стенли Липпман торрент бесплатно.
Комментарии