Итераторы.. почему используют их? [дубликат]

Исключение нулевого указателя генерируется, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  1. Вызов метода экземпляра объекта null.
  2. Доступ или изменение поля объекта null.
  3. Принимая длину null, как если бы это был массив.
  4. Доступ или изменение слотов null, как если бы это был массив.
  5. Бросок null как будто это было значение Throwable.

Приложения должны бросать экземпляры этого класса, чтобы указать на другие незаконные использования объекта null.

Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

22
задан Konrad 7 October 2010 в 15:12
поделиться

6 ответов

Обратите внимание, что обычно реализация вектора не будет использовать "интервал" в качестве типа индекса/размера. Таким образом, Ваш код по крайней мере вызовет предупреждения компилятора.

Степень универсальности

Итераторы увеличивают степень универсальности Вашего кода.

, Например:

typedef std::vector<int> Container ;

void doSomething(Container & p_aC)
{
    for(Container::iterator it = p_aC.begin(), itEnd = p_aC.end(); it != itEnd; ++it)
    {
       int & i = *it ; // i is now a reference to the value iterated
       // do something with "i"
    }
}

Теперь, давайте предположим изменение вектора в список (потому что в случае, список теперь лучше). Только необходимо изменить объявление определения типа и перекомпилировать код.

Должен Вы использовать основанный на индексе код вместо этого, он должен был бы быть переписан.

Доступ

итератор должен быть просмотрен как своего рода супер указатель. Это "указывает" на значение (или, в случае карт, к паре ключа/значения).

, Но это имеет методы для перемещения в следующий объект в контейнере. Или предыдущее. Некоторые контейнеры предлагают даже произвольный доступ (вектор и двухсторонняя очередь).

Алгоритмы

Большинство алгоритмов STL работает над итераторами или над диапазонами итераторов (снова из-за степени универсальности). Вы не будете в состоянии использовать индекс, здесь.

27
ответ дан 29 November 2019 в 04:17
поделиться

Используя итераторы позволяет Вашему коду быть агностиком о реализации Вашего контейнера. Если произвольный доступ для Вашего контейнера является дешевым, нет большого мудрого производительностью различия.

, Но в большом количестве случаев Вы не будете знать, имеет ли это место. Если Вы пробуете, действительно используют Ваш метод в связанном списке, например, с индексированием, контейнер оказывается перед необходимостью обходить список на каждом повторении для нахождения элемента.

Поэтому, если Вы не знаете наверняка, что произвольный доступ к Вашему контейнеру является дешевым, используйте итератор.

17
ответ дан 29 November 2019 в 04:17
поделиться

Если Вы используете итераторы в качестве аргументов Вашей функции, можно разъединить ее от типа используемого "контейнера". Например, Вы могли бы направить результаты функции подключиться с консоли к выводу, а не вектору (пример ниже). Этот прием может быть чрезвычайно мощным для сокращения связи между Вашими классами. Слабо связанные классы намного легче протестировать.

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template <typename InputIterator, typename OutputIterator>
void AddOne(InputIterator begin, InputIterator end, OutputIterator dest)
{
    while (begin != end)
    {
        *dest = *begin + 1;
        ++dest;
        ++begin;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<int> data;
    data.push_back(1);
    data.push_back(2);
    data.push_back(3);

    // Compute intermediate results vector and dump to console
    vector<int> results;
    AddOne(data.begin(), data.end(), back_inserter(results));
    copy(results.begin(), results.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    // Compute results and send directly to console, no intermediate vector required
    AddOne(data.begin(), data.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    return 0;
}
2
ответ дан 29 November 2019 в 04:17
поделиться

В Вашем примере вызов к vecVector.size () менее эффективен, чем использование итератора. Итератор по существу инкапсулирует Вас от необходимости волноваться о размере контейнера, выполняемого с помощью итераций на. Кроме того, итератор не делает необходимый, должны войти в последовательный порядок. Это просто должно ответить на вызов .next любым способом, которым это считает целесообразным.

1
ответ дан 29 November 2019 в 04:17
поделиться

Ну, с одной стороны, вышеупомянутое больше не будет работать, если Вы превратите тот вектор в список.

Итераторы позволяют Вам создавать шаблоны функций, которые не должны знать тип контейнера, они продолжают работать. Можно даже сделать следующее:

#include <algorithm>

void printvalue(double s)
{
    // Do something with s
}

int _tmain(int argc, _TCHAR* argv[])
{
    double s[20] = {0};

    std::for_each(s, s+20, printvalue);

    return 0;
}

Поэтому стандартный указатель является также допустимым итератором для for_each.

Dave

1
ответ дан 29 November 2019 в 04:17
поделиться

Итератор является главным образом более высоким уровнем абстракции.

Ваш отрывок предполагает, что контейнер может быть индексирован. Это верно для std::vector<> и некоторые другие контейнеры, например, необработанные массивы.

, Но std::set<> испытывает недостаток в индексации полностью, и индексный оператор std::map<> вставит любой аргумент, предоставляется ему в карту - не ожидаемое поведение в Вашем for - цикл.

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

1
ответ дан 29 November 2019 в 04:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: