С.Б. Липпман, Ж. Лажойе - Язык программирования С++ Вводный курс (1114944), страница 44
Текст из файла (страница 44)
list не поддерживает адресную арифметику, поскольку его элементы нерасполагаются в непрерывной области памяти. Следующее выражение к спискунеприменимо:ilist.begin() + 2;так как для перемещения на два элемента необходимо два раза перейти по адресу,содержащемуся в закрытом члене next. У классов vector и deque перемещение на дваэлемента означает прибавление 2 к указателю на текущий элемент. (Адреснаяарифметика рассматривается в разделе 3.3.)Объект контейнерного типа может быть инициализирован парой итераторов,обозначающих начало и конец последовательности копируемых в новый объектэлементов.
(Второй итератор должен указывать на элемент, следующий за последним#include <vector>#include <string>#include <iostream>int main(){vector<string> svec;string intext;while ( cin >> intext )svec.push_back( intext );// обработать svec ...копируемым.) Допустим, есть вектор:}Вот как можно определить новые векторы, инициализируя их элементами первогоint main() {vector<string> svec;// ...// инициализация svec2 всеми элементами svecvector<string> svec2( svec.begin(), svec.end() );// инициализация svec3 первой половиной svecvector<string>::iterator it =svec.begin() + svec.size()/2;vector<string> svec3 ( svec.begin(), it );// ...вектора:}259С++ для начинающихИспользование специального типа istream_iterator (о нем рассказывается в разделе#include <vector>#include <string>#include <iterator>int mainQ{// привязка istream_iterator к стандартному вводуistream_iterator<string> infile( cin );// istream_iterator, отмечающий конец потокаistream_iterator<string> eos;// инициализация svec элементами, считываемыми из cin;vector<string> svec( infile, eos );// ...12.4.3) упрощает чтение элементов из входного потока в svec:}Кроме итераторов, для задания диапазона значений, инициализирующих контейнер,можно использовать два указателя на массив встроенного типа.
Пусть есть следующий#include <string>string words[4] = {"stately", "plump", "buck", "mulligan"массив строк:};Мы можем инициализировать вектор с помощью указателей на первый элемент массиваи на элемент, следующий за последним:vector< string > vwords( words, words+4 );Второй указатель служит “стражем”: элемент, на который он указывает, не копируется.int ia[6] = { 0, 1, 2, 3, 4, 5 };Аналогичным образом можно инициализировать список целых элементов:list< int > ilist( ia, ia+6 );В разделе 12.4 мы снова обратимся к итераторам и опишем их более детально. Сейчасинформации достаточно для того, чтобы использовать итераторы в нашей системетекстового поиска.
Но прежде чем вернуться к ней, рассмотрим некоторыедополнительные операции, поддерживаемые контейнерами.Упражнение 6.9Какие ошибки допущены при использовании итераторов:260С++ для начинающихconst vector< int > ivec;vector< string >svec;list< int >ilist;(a)(b)(c)(d)vector<int>::iterator it = ivec.begin();list<int>::iteratorit = ilist.begin()+2;vector<string>::iterator it = &svec[0];for ( vector<string>::iteratorit = svec.begin(); it != 0; ++it )// ...Упражнение 6.10int ia[7] = { 0, 1, 1, 2, 3, 5, 8 };string sa[6] = {"Fort Sumter", "Manassas", "Perryville", "Vicksburg","Meridian", "Chancellorsvine" };(a)(b)(c)(d)(e)vector<string> svec( sa, &sa[6] );list<int> ilist( ia+4, ia+6 );list<int> ilist2( ilist.begin(), ilist.begin()+2 );vector<int> ivec( &ia[0], ia+8 );list<string> slist( sa+6, sa );Найдите ошибки в использовании итераторов:(f) vector<string> svec2( sa, sa+6 );6.6.
Операции с последовательными контейнерамиФункция-член push_back() позволяет добавить единственный элемент в конецконтейнера. Но как вставить элемент в произвольную позицию? А целуюпоследовательность элементов? Для этих случаев существуют более общие операции.vector< string > svec;list< string > slist;string spouse( "Beth" );slist.insert( slist.begin(), spouse );Например, для вставки элемента в начало контейнера можно использовать:svec.insert( svec.begin(), spouse );Первый параметр функции-члена insert() (итератор, адресующий некоторый элементконтейнера) задает позицию, а второй – вставляемое перед этой позицией значение.
Впримере выше элемент добавляется в начало контейнера. А так можно реализоватьвставку в произвольную позицию:261С++ для начинающих262string son( "Danny" );list<string>::iterator iter;iter = find( slist.begin(), slist.end(), son );slist.insert( iter, spouse );Здесь find() возвращает позицию элемента в контейнере, если элемент найден, либоитератор end(), если ничего не найдено. (Мы вернемся к функции find() в концеследующего раздела.) Как можно догадаться, push_back() эквивалентен следующей// эквивалентный вызов: slist.push_back( value );записи:slist.insert( slist.end(), value );Вторая форма функции-члена insert() позволяет вставить указанное количествоодинаковых элементов, начиная с определенной позиции.
Например, если мы хотимvector<string> svec;string anna( "Anna" );добавить десять элементов Anna в начало вектора, то должны написать:svec.insert( svec.begin(), 10, anna );insert() имеет и третью форму, помогающую вставить в контейнер несколькоэлементов. Допустим, имеется следующий массив:string sarray[4] = { "quasi", "simba", "frollo", "scar" };Мы можем добавить все его элементы или только некоторый диапазон в наш векторsvec.insert( svec.begin(), sarray, sarray+4 );svec.insert( svec.begin() + svec.size()/2,строк:sarray+2, sarray+4 );// вставляем элементы svec// в середину svec_twosvec_two.insert( svec_two.begin() + svec_two.size()/2,Такой диапазон отмечается и с помощью пары итераторовsvec.begin(), svec.end() );С++ для начинающихlist< string > slist;// ...// вставляем элементы svec// перед элементом, содержащим stringVallist< string >::iterator iter =find( slist.begin(), slist.end(), stringVal );или любого контейнера, содержащего строки:14slist.insert( iter, svec.begin(), svec.end() );6.6.1.
УдалениеВ общем случае удаление осуществляется двумя формами функции-члена erase().Первая форма удаляет единственный элемент, вторая – диапазон, отмеченный паройитераторов. Для последнего элемента можно воспользоваться функцией-членомpop_back().При вызове erase() параметром является итератор, указывающий на нужный элемент.В следующем фрагменте кода мы воспользуемся обобщенным алгоритмом find() дляstring searchValue( "Quasimodo" );list< string >::iterator iter =find( slist.begin(), slist.end(), searchValue );if ( iter != slist.end() )нахождения элемента и, если он найден, передадим его адрес функции-члену erase().slist.erase( iter );Для удаления всех элементов контейнера или некоторого диапазона можно написать// удаляем все элементы контейнераslist.erase( slist.begin(), slist.end() );// удаляем элементы, помеченные итераторамиlist< string >::iterator first, last;first = find( slist.
begin(), slist.end(), vail );last = find( slist.begin(), slist.end(), va12 );// ... проверка first и lastследующее:slist.erase( first, last );14 Последняя форма insert() требует, чтобы компилятор работал с шаблонамифункций-членов. Если ваш компилятор еще не поддерживает это свойство стандарта С++,то оба контейнера должны быть одного типа, например два списка или два вектора,содержащих элементы одного типа.263С++ для начинающихПарной по отношению к push_back() является функция-член pop_back(), удаляющаяvector< string >::iterator iter = buffer.begin();for ( ; iter != buffer.end(), iter++ ){slist.push_back( *iter );if ( ! do_something( slist ))slist.pop_back();из контейнера последний элемент, не возвращая его значения:}6.6.2. Присваивание и обменЧто происходит, если мы присваиваем один контейнер другому? Оператор присваиваниякопирует элементы из контейнера, стоящего справа, в контейнер, стоящий слева от знака// svecl содержит 10 элементов// svec2 содержит 24 элемента// после присваивания оба содержат по 24 элементаравенства.
А если эти контейнеры имеют разный размер? Например:svecl = svec2;Контейнер-адресат (svec1) теперь содержит столько же элементов, сколько контейнеристочник (svec2). 10 элементов, изначально содержавшихся в svec1, удаляются (длякаждого из них вызывается деструктор класса string).Функция обмена swap() может рассматриваться как дополнение к операцииприсваивания. Когда мы пишем:svecl.swap( svec2 );svec1 после вызова функции содержит 24 элемента, которые он получил бы в результатеприсваивания:svecl = svec2;но зато теперь svec2 получает 10 элементов, ранее находившихся в svec1.
Контейнеры“обмениваются” своим содержимым.6.6.3. Обобщенные алгоритмыОперации, описанные в предыдущих разделах, составляют набор, поддерживаемыйнепосредственно контейнерами vector и deque. Согласитесь, что это весьма небогатыйинтерфейс и ему явно не хватает базовых операций find(), sort(), merge() и т.д.Планировалось вынести общие для всех контейнеров операции в набор обобщенныхалгоритмов, которые могут применяться ко всем контейнерным типам, а также кмассивам встроенных типов. (Обобщенные алгоритмы описываются в главе 12 и вПриложении.) Эти алгоритмы связываются с определенным типом контейнера с264С++ для начинающих265помощью передачи им в качестве параметров пары соответствующих итераторов.
Вот как#include <list>#include <vector>int ia[ 6 ] = { 0, 1, 2, 3, 4, 5 };vector<string> svec;list<double> dtist;// соответствующий заголовочный файл#include <algorithm>vector<string>::iterator viter;list<double>::iterator liter;#int *pia;// find() возвращает итератор на найденный элемент// для массива возвращается указатель ...pia =find( &ia[0], &ia[6], some_int_value );liter = find( dlist.begin(), dlist.end(), some_double_value );выглядят вызовы алгоритма find() для списка, вектора и массива разных типов:viter = find( svec.begin(), svec.end(), some_string_value );Контейнер list поддерживает дополнительные операции, такие, как sort() и merge(),поскольку в нем не реализован произвольный доступ к элементам. (Эти операцииописаны в разделе 12.6.)Теперь вернемся к нашей поисковой системе.Упражнение 6.11int ia[] = { 1, 5, 34 };int ia2[] = { 1, 2, 3 };int ia3[] = { 6, 13, 21, 29, 38, 55, 67, 89 };Напишите программу, в которой определены следующие объекты:vector<int> ivec;Используя различные операции вставки и подходящие значения ia,модифицируйте вектор ivec так, чтобы он содержал последовательность:ia2 и ia3,{ 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 }Упражнение 6.12int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };Напишите программу, определяющую данные объекты:list<int> ilist( ia, ia+11 );Используя функцию-член erase() с одним параметром, удалите из ilist все нечетныеэлементы.С++ для начинающих6.7.