Как найти позицию итератора?

221
24 февраля 2017, 01:19

Есть вектор строк. Прохожу в цикле по каждой строке, и в каждой строке опять в цикле прохожу по каждому символу и ищу '0'. Надо вывести позицию этого символа. И назрел вопрос, а можно ли это сделать не используя дополнительный счетчик? То есть обойтись только итераторами. За ранее благодарю.

for(auto line = lines.begin(); line != lines.end(); ++line)
    {
        for(auto symbol = (*line).begin(); symbol != (*line).end(); ++symbol)
        {
            if (*symbol == '0')
            {
                cout << "Номер символа: " << /*номер символа*/ << endl;
            }
        }
    }
Answer 1

В вашем конкретном случае нечего и огород городить: вычисление номера символа в строке (подразумевая std::string) вы можете это сделать просто как symbol - line->begin().

Однако в общем, более абстрактном случае, если вы реализуете алгоритм, который по своей сути не требует произвольного доступа (random access) к используемой структуре данных, а обходится лишь последовательным доступом (sequential access), то более разумным решением, возможно, будет как-раз таки использовать именно счетчик. Таким образом вы по-прежнему сохраните последовательную структуру вашего алгоритма, т.е. решите задачу в рамках менее требовательного контракта последовательно доступа.

Используя вычитание итераторов вы искусственно привносите в чисто последовательный алгоритм существенно более сильное требование поддержки произвольного доступа. Не надо неоправданно накладывать на структуры данных чересчур ужесточенные требования. Если задача может быть решена эффективно в рамках идеи последовательного доступа - то лучше решить ее в рамках идеи последовательного доступа.

Например, если в чисто последовательном алгоритме вам завтра понадобится заменить вектор на список, то вам в реализации вашего алгоритма не придется делать никаких переделок. Но достаточно добавить в такой алгоритм вычитание итераторов - и все становится намного сложнее.

Будьте также осторожны с функциями типа std::distance. Эта функция предназначена в первую очередь для вынужденного сокрытия неэффективностей, т.е. для того, чтобы тихо вычислять расстояние между итераторами даже тогда, когда итераторы не поддерживают эффективного вычисления расстояния. То есть std::distance - это практически всегда костыль для очень узкоспециализированных ситуаций из разряда "тут невозможно обойтись без расстояния, даже если его вычисление неэффективно". Таких ситуаций надо старательно избегать.

Answer 2

Для этого имеется стандартная функция std::distance, объявленная в заголовке <iterator>.

Например,

cout << "Номер символа: " << std::distance( (*line).begin(), symbol ) << endl;

Для итераторов произвольного доступа, как в вашем случае, можно просто вычесть один итератор из другого

cout << "Номер символа: " << symbol - (*line).begin() << endl;

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

for ( size_t i = 0; i != line->size(); ++i )
{
    if ( ( *line )[i] == '0')
    {
        cout << "Номер символа: " << i << endl;
    }
}

и использовать этот индекс в качестве значения позиции.

READ ALSO
Как достать файл из MFT?

Как достать файл из MFT?

DeviceIoControl с использованием управляющего кода FSCTL_GET_RETRIEVAL_POINTERS позволяет извлечь информацию о физическом расположении файла на дискеОднако,...

365
Очередь через массив

Очередь через массив

Доброго времени суток! Нужно создать очередь на основе массиваПоняла это буквально и написала так

271
Очень медленно выполняется MySQL запрос

Очень медленно выполняется MySQL запрос

Всем приветИмеется вот такой вот запрос

302