В итераторах C++ в контейнер напоминающих указателей в массив (я предполагаю, что вы знакомы с указателями). Существуют разные варианты итераторов, но в конце они всего лишь способ ссылаться на элементы внутри контейнера (через операторы разыменования *
и ->
) и трансверсать элементы в контейнере.
Важная часть - это не реализация, а концепция. Вам не нужно знать, как внедряется итератор в список или вектор (или как они отличаются во многих случаях), только то, что он предоставляет. Итераторы в разных контейнерах будут иметь разные реализации (для списка он будет следовать указателю next
в узле, для карты он будет следовать либо ребенку right
, либо указателю parent
сбалансированного дерева. Фактически итераторы в один и тот же контейнер могут быть реализованы по-разному (и некоторые компиляторы имеют более одной реализации для любого данного контейнера) в зависимости от флагов или режима компиляции. Но тем не менее важная часть состоит в том, что вам действительно все равно, как они, именно то, что они позволяют вам делать .
в качестве простого примера, в г реализация STL ++ std::vector
содержит три указателя, что-то вроде:
//...
class vector {
T * _b; // beginning of allocated memory
T * _e; // one past the last inserted element
T * _c; // one past the end of the allocated memory
//...
}
такой, что size() = (_e - _b)/sizeof(T)
и capacity = (_c - _b)/sizeof(T)
. При реализации этого вектора, вы можете использовать сырой указатель в качестве итератора:
//...
class vector {
public:
typedef T* iterator;
T* begin() { return _b; }
T* end() { return _e; }
//...
}
, но вы также можете создавать более сложные (медленнее, но безопаснее) реализации итераторов, как проверяется итераторы, которые будут вызывать утверждение, если итератор имеет был признано недействительным (этот код упрощен только для целей выборки):
template <typename T>
class checked_iterator {
public:
checked_iterator(std::vector<T> & v, std::size_t e)
: _check_begin(v._b), _vector(v), _pos(v._b + e)
{}
T& operator*() {
assert(_check_begin == _vector._b && "Dereferencing an invalidated iterator");
return *_pos;
}
// ...
private:
T * _pos;
T const * const _check_begin;
std::vector<T>& _vector;
};
Этих итератора реализация обнаружит разыменования недопустимого итератора (только в случае целого вектора перемещения, но, сохраняя больше данных он может сделать полное check) и прервет выполнение некорректной программы во время разработки. С точки зрения пользователя это был бы простой RandomAccessIterator (это должно быть, это требование для векторных итераторов), но за кулисами он предоставит механизм для выявления в противном случае трудно обнаружить ошибки.
Это подход в компиляторах VS: в режиме отладки (и в зависимости от флагов компилятора) он будет использовать медленные итераторы, которые помогут обнаружить доступ через недействительные итераторы (для вектора итератор недействителен всякий раз, когда элемент добавляется в контейнер). В то же время, изменяя флагов компилятора, вы можете получить реализацию простого raw-указателя, которая будет намного быстрее для производственных систем, но было бы гораздо сложнее отладить недействительное использование итератора.
В Java и C# на самом деле они объекты, реализующие несколько простых операций (в Java hasNext()
, next()
и remove()
), которые позволяют секущей целого контейнера Hidding, как реализуется контейнер.Они очень похожи в том, что намерение заключается в инкапсулировании операций, выполняемых на конкретном контейнере из кода пользователя.
Важным отличием является то, что в обоих случаях вы можете использовать их для итерации по всему контейнеру, но в C++ они сопоставимы, и вы можете перебирать любые два итератора в один и тот же контейнер. Например, на карте, содержащей вашу телефонную книгу города, вы можете использовать операции, чтобы получить итератор в первое имя, начинающееся с ac, и другой поиск, чтобы получить первый элемент, имя которого начинается с «d» (при условии упорядочения имен), и вы может использовать любой STL (или ваш собственный) алгоритм с этими двумя итераторами для выполнения операции только для этого подмножества людей.
Концепции итератора различаются в C++ и Java/C#. В обоих случаях они являются инкрементальными и разыскиваемыми объектами, но набор операций и использование различаются. –