27 Iterators library [iterators]

27.2 Iterator requirements [iterator.requirements]

27.2.1 In general [iterator.requirements.general]

Итераторы - это обобщение указателей, которые позволяют программе на C ++ единообразно работать с различными структурами данных (контейнерами). Чтобы иметь возможность создавать шаблонные алгоритмы, которые правильно и эффективно работают с различными типами структур данных, библиотека формализует не только интерфейсы, но также семантику и предположения о сложности итераторов. Итератор ввода i поддерживает выражение *i, в результате чего получается значение некоторого типа объекта T, называемого value type итератором. Итератор выводаi имеет непустой набор типов, относящихся writable к итератору; для каждого такого типа допустимоTвыражение,*i = oгдеo - значение типаT. Итератор, i для которого выражение (*i).m четко определено, поддерживает выражение i->m с той же семантикой, что и (*i).m. Для каждого типа итератора, X для которого определено равенство, существует соответствующий целочисленный тип соdifference type знаком, называемый итератором.

Поскольку итераторы являются абстракцией указателей, их семантика является обобщением большей части семантики указателей в C ++. Это гарантирует, что каждый шаблон функции, который принимает итераторы, также работает с обычными указателями. Настоящий стандарт определяет пять категорий итераторов, в соответствии с операциями , определенными на них: input iterators, output iterators, forward iterators, bidirectional iterators и random access iterators, как показано в таблице93.

Таблица93 - отношения между категориями итераторов
Произвольный доступ Двунаправленный Вперед Вход
Выход

Прямые итераторы удовлетворяют всем требованиям итераторов ввода и могут использоваться всякий раз, когда указан итератор ввода; Двунаправленные итераторы также удовлетворяют всем требованиям прямых итераторов и могут использоваться всякий раз, когда указан прямой итератор; Итераторы произвольного доступа также удовлетворяют всем требованиям двунаправленных итераторов и могут использоваться всякий раз, когда указан двунаправленный итератор.

Вызываются итераторы, которые дополнительно удовлетворяют требованиям итераторов выводаmutable iterators. Неизменяемые итераторы называютсяconstant iterators.

В дополнение к требованиям этого подпункта для типа итератора должна быть предусмотрена вложенность, typedef-names указанная в[iterator.traits]. [ Note: Либо тип итератора должен предоставлять их typedef-names напрямую (в этом случае получать ихiterator_­traits автоматически), либоiterator_­traits специализация должна предоставлять их. ]end note

Итераторы, которые дополнительно удовлетворяют требованию о том, что для целочисленных значенийn и значений итераторов с возможностью разыменованияa и(a + n), *(a + n) эквивалентно*(addressof(*a) + n), вызываютсяcontiguous iterators. [ Note: Например, тип «указатель наint» является непрерывным итератором, ноreverse_­iterator<int *> это не так. Для допустимого диапазона итератора[a,b) с возможностью разыменованияaсоответствующий диапазон, обозначенный указателями, равен [addressof(*a),addressof(*a) + (b - a)); b не может быть разыменован. ]end note

Так же, как обычный указатель на массив гарантирует, что существует значение указателя, указывающее за последним элементом массива, так и для любого типа итератора существует значение итератора, указывающее за последним элементом соответствующей последовательности. Эти значения называются past-the-end значениями. Значения итератора ,i для которых выражение *i определенно называется dereferenceable. Библиотека никогда не предполагает, что последние значения могут быть разыменованы. Итераторы также могут иметь особые значения, не связанные с какой-либо последовательностью. [ Example: После объявления неинициализированного указателя x (как в случае int* x;) x всегда следует предполагать, что он имеет единственное значение указателя. ] Результаты большинства выражений не определены для сингулярных значений; единственными исключениями являются уничтожение итератора, содержащего сингулярное значение, присвоение неособого значения итератору, содержащему сингулярное значение, и, для итераторов, удовлетворяющих требованиям, использование итератора с инициализированным значением в качестве источника копирование или перемещение. [ Эта гарантия не предоставляется для инициализации по умолчанию, хотя различие имеет значение только для типов с тривиальными конструкторами по умолчанию, такими как указатели или агрегаты, содержащие указатели. ] В этих случаях единственное значение перезаписывается так же, как и любое другое значение. Разыменяемые значения всегда не единственные.end exampleDefaultConstructible Note: end note

Итератор j вызывается reachable из итератора i тогда и только тогда, когда существует конечная последовательность применений выражения, ++i которое делает i == j. Если j доступен из i, они относятся к элементам той же последовательности.

Большинство алгоритмических шаблонов библиотеки, которые работают со структурами данных, имеют интерфейсы, использующие диапазоны. A range - пара итераторов, обозначающих начало и конец вычисления. Диапазон[i, i) - это пустой диапазон; в общем, диапазон[i, j) относится к элементам в структуре данных, начиная с элемента, на который указывает, i и до, но не включая элемент, на который указывает j. Диапазон[i, j) действителен тогда и только тогда, когда j он доступен из i. Результат применения функций библиотеки к недопустимым диапазонам не определен.

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

Уничтожение итератора может сделать недействительными указатели и ссылки, ранее полученные от этого итератора.

invalid Итератора является итератор , который может быть вырожденной.261

В следующих разделах, a и b величины означают типа X илиconst X, difference_­type иreference относятся к типам ,iterator_­traits<X>​::​difference_­type и iterator_­traits<X>​::​reference, соответственно, n обозначает значение difference_­type, u, tmpи цветом,m обозначают идентификаторы, r обозначает значение X&, t обозначает значение типа значения T, o обозначает значение некоторого типа который доступен для записи итератору вывода. [ Note: Для типа итератораX должен быть экземплярiterator_­traits<X>. ]end note

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

27.2.2 Iterator [iterator.iterators]

ВIterator требования легли в основу концепции итератора систематики; каждый итератор удовлетворяетIterator требованиям. Этот набор требований определяет операции для разыменования и увеличения итератора. Большинство алгоритмов потребует дополнительных действий для read илиwrite значения, или обеспечить более богатый набор итератор движений ([forward.iterators], [bidirectional.iterators],[random.access.iterators]).

ТипX удовлетворяетIterator требованиям, если:

  • X удовлетворяетCopyConstructible,CopyAssignableи Destructible требования ([utility.arg.requirements]) и lvalues типаX являютсяswappable, и

  • выражения в таблице94 действительны и имеют указанную семантику.

Таблица94 - Требования к итератору
ВыражениеТип возвратаОперативныйУтверждение / примечание
семантикадо / после состояния
*r неопределенные Requires:r разыменуемо.
++r X&

27.2.3 Input iterators [input.iterators]

Класс или указатель типа X удовлетворяет требования входного итератора для типа значения ,T если X удовлетворяютIterator и EqualityComparable требования и выражение , приведенные в таблице95 , действительны и имеют указанную семантику.

В Таблице95этот термин the domain of == используется в обычном математическом смысле для обозначения набора значений, для которых == (требуется) определение. Этот набор может меняться со временем. Каждый алгоритм предъявляет дополнительные требования к области == значений используемых итераторов. Эти требования могут быть выведены из использования алгоритма== и!=. [ Example: Вызовfind(a,b,x) определяется только в том случае, если значениеa имеет свойство,p определенное следующим образом: b имеет свойство,p а значениеi имеет свойствоp if (*i==x) или if (*i!=x и ++i имеет свойство p). ]end example

Таблица95 - Требования к итератору ввода (в дополнение к Iterator)
ВыражениеТип возвратаОперативныйУтверждение / примечание
семантикадо / после состояния
a != b контекстно конвертируемый вbool !(a == b) Requires:(a, b) находится в домене==.
*a reference, конвертируемый вT Requires:a разыменуемо.
Выражение
(void)*a, *a эквивалентно*a.
Еслиa == b и(a, b) находится в домене,== то*a эквивалентно*b.
a->m (*a).m Requires:a разыменуемо.
++r X& Requires:r разыменуемо.
Postconditions:r разыменован или оконченr ;
любые копии предыдущего значенияr больше не должны быть разыменованными или находиться в домене==.
(void)r++ эквивалентно(void)++r
*r++ конвертируемый вT { T tmp = *r;
++r;
return tmp; }

[ Note: Для итераторов ввода a == b не означает ++a == ++b. (Равенство не гарантирует свойство подстановки или ссылочную прозрачность.) Алгоритмы на итераторах ввода никогда не должны пытаться пройти через один и тот же итератор дважды. Это должны быть single pass алгоритмы. Тип значенияT не обязательно должен бытьCopyAssignable типом. Эти алгоритмы могут использоваться с istreams в качестве источника входных данных через istream_­iterator шаблон класса. ]end note

27.2.4 Output iterators [output.iterators]

Тип класса или указателя X удовлетворяет требованиям итератора вывода, еслиX удовлетворяетIterator требованиям, а выражения в таблице96 действительны и имеют указанную семантику.

Таблица96 - Требования к итератору вывода (в дополнение к Iterator)
ВыражениеТип возвратаОперативныйУтверждение / примечание
семантикадо / после состояния
*r = o результат не используется Remarks:  После этой операцииr разыменование не требуется.
Postconditions:r является увеличиваемым.
++r X& &r == &++r.
Remarks:  После этой операцииr разыменование не требуется.
Postconditions:r является увеличиваемым.
r++ конвертируемый вconst X& { X tmp = r;
++r;
return tmp; }
Remarks:  После этой операцииr разыменование не требуется.
Postconditions:r является увеличиваемым.
*r++ = o результат не используется Remarks:  После этой операцииr разыменование не требуется.
Postconditions:r является увеличиваемым.

[ Note: Единственное допустимое использование - operator* находится в левой части оператора присваивания. Assignment through the same value of the iterator happens only once. Алгоритмы на итераторах вывода никогда не должны пытаться дважды пройти через один и тот же итератор. Это должны быть single pass алгоритмы. Равенство и неравенство нельзя определить. Алгоритмы, которые принимают итераторы вывода, могут использоваться с ostreams в качестве места назначения для размещения данных через ostream_­iterator класс, а также с итераторами вставки и указателями вставки. ]end note

27.2.5 Forward iterators [forward.iterators]

Тип класса или указателя X удовлетворяет требованиям прямого итератора, если

  • X удовлетворяет требованиямinput iterator,

  • X удовлетворяетDefaultConstructible requirements,

  • еслиX изменяемый итератор,reference это ссылка наT; еслиX постоянный итератор,reference это ссылка наconst T,

  • выражения в таблице97 действительны и имеют указанную семантику, и

  • объекты типаX предлагают многопроходную гарантию, описанную ниже.

Область== прямых итераторов - это область итераторов той же базовой последовательности. Однако итераторы с инициализацией значения могут сравниваться и должны сравниваться наравне с другими итераторами с инициализацией значения того же типа. [ Note: Итераторы с инициализацией значения ведут себя так, как если бы они ссылались на конец одной и той же пустой последовательности. ]end note

Два разыменяемых итератораa иb типаX предлагают multi-pass guarantee if:

  • a == b подразумевает++a == ++b и

  • X является типом указателя или выражение (void)++X(a), *a эквивалентно выражению*a.

[ Note: Требование, которое a == b подразумевает ++a == ++b (что неверно для итераторов ввода и вывода) и снятие ограничений на количество назначений через изменяемый итератор (которое применяется к итераторам вывода), позволяет использовать многопроходные однонаправленные алгоритмы с прямыми итераторами. ]end note

Таблица97 - Требования прямого итератора (в дополнение к итератору ввода)
ВыражениеТип возвратаОперативныйУтверждение / примечание
семантикадо / после состояния
r++ конвертируемый вconst X& { X tmp = r;
++r;
return tmp; }
*r++ reference

Еслиa иb равны, то либоa и, либоb разыменуемы, либо ни один из них не разыменован.

Еслиa иb оба разыменованы, тоa == b тогда и только тогда, когда *a и*b привязаны к одному и тому же объекту.

27.2.6 Bidirectional iterators [bidirectional.iterators]

Тип класса или указателя X удовлетворяет требованиям двунаправленного итератора, если, помимо удовлетворения требований для прямых итераторов, допустимы следующие выражения, как показано в таблице98.

Таблица98 - Требования к двунаправленному итератору (в дополнение к прямому итератору)
ВыражениеТип возвратаОперативныйУтверждение / примечание
семантикадо / после состояния
--r X& Requires: существуетs такое чтоr == ++s.
Postconditions:r разыменуемо.
--(++r) == r.
--r == --s подразумеваетr == s.
&r == &--r.
r-- конвертируемый вconst X& { X tmp = r;
--r;
return tmp; }
*r-- reference

[ Note: Двунаправленные итераторы позволяют алгоритмам перемещать итераторы вперед и назад. ]end note

27.2.7 Random access iterators [random.access.iterators]

Тип класса или указателя X удовлетворяет требованиям итератора с произвольным доступом, если, помимо удовлетворения требований для двунаправленных итераторов, допустимы следующие выражения, как показано в таблице99.

Таблица99 - Требования к итератору произвольного доступа (в дополнение к двунаправленному итератору)
ВыражениеТип возвратаОперативныйУтверждение / примечание
семантикадо / после состояния
r += n X& { difference_­type m = n;
if (m >= 0)
while (m--)
++r;
else
while (m++)
--r;
return r; }
a + n
n + a
X { X tmp = a;
return tmp += n; }
a + n == n + a.
r -= n X& return r += -n; Requires: абсолютное значениеn находится в диапазоне представимых значенийdifference_­type.
a - n X { X tmp = a;
return tmp -= n; }
b - a difference_­type return n Requires: существует такое значениеn типаdifference_­type , чтоa + n == b.
b == a + (b - a).
a[n] конвертируемый вreference *(a + n)
a < b контекстно конвертируемый вbool b - a > 0 < отношение полного порядка
a > b контекстно конвертируемый вbool b < a > отношение полного порядка, противоположное<.
a >= b контекстно конвертируемый вbool !(a < b)
a <= b контекстно конвертируемый вbool. !(a > b)