Итератор для второго до последнего элемента в списке - PullRequest
16 голосов
/ 21 июня 2011

В настоящее время у меня есть следующее для цикла:

for(list<string>::iterator jt=it->begin(); jt!=it->end()-1; jt++)

У меня есть список строк, который находится в большем списке (list<list<string> >). Я хочу перебрать содержимое внутреннего списка, пока не доберусь до 2-го до последнего элемента. Это потому, что я уже обработал содержимое последнего элемента, и у меня нет причин обрабатывать их снова.

Однако использование it->end()-1 недопустимо - я не могу использовать оператор - здесь. Хотя я мог бы использовать оператор --, это уменьшило бы этот последний итератор в каждом цикле.

Я считаю, что список STL является двусвязным списком, поэтому, с моей точки зрения, это должно быть возможно.

Обратить? Заранее спасибо

Ответы [ 5 ]

8 голосов
/ 22 июня 2011

Необходимая рекомендация использовать стандартную библиотеку:

std::for_each(lst.begin(), --lst.end(), process);

Если вы не хотите хлопот с созданием функтора [я почти никогда не делаю], и вы не можете использовать обратные итераторы, поднимитеконечная проверка из цикла:

for(iterator i = lst.begin(), j = --lst.end(); i != j; ++i) {
    // do
    // stuff
}

Или вы можете просто доверить оптимизатору признать, что ему не нужно повторно создавать конечное условие, и выполнить сам подъем.Насколько это надежно, зависит от реализации списка, от того, насколько сложен ваш код цикла и насколько хорош ваш оптимизатор.

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

6 голосов
/ 21 июня 2011

Список итераторов не является случайным итератором. Вы должны сделать следующее:

if ( ! it->empty() )
{
  list<string>::iterator test = it->end();
  --test;
  for( list<string>::iterator jt = it->begin(); jt != test; ++jt )
  {
  ...
  }
}

Еще одна вещь: используйте ++jt против jt++. jt++ исходный код обычно выглядит примерно так:

iterator operator++ (int i)
{
  iterator temp = (*this);
  ++(*this);
  return temp;
}; 
4 голосов
/ 30 января 2018

В c ++ 11 и более поздних версиях лучшим ответом будет использование std::prev

for(iterator i = lst.begin(); i != std::prev(lst.end()); ++i) {
    // do
    // stuff
}

Документация для std :: prev on http://en.cppreference.com/w/cpp/iterator/prev говорит,

Хотя выражение --c.end () часто компилируется, это не гарантируется: c.end () является выражением rvalue, и не существует требования к итератору, которое указывает, что уменьшение значения r гарантирует значение Работа. В частности, когда итераторы реализованы в виде указателей, --c.end () не компилируется, а std :: prev (c.end ()) - компилируется.

Я считаю, что std :: prev () в пустом списке не определено, поэтому вам может потребоваться заключить это в !i.empty() условие

4 голосов
/ 21 июня 2011

как насчет обратного итератора?

for(list<string>::reverse_iterator jt=++(it->rbegin()); jt!=it->rend(); jt++)
4 голосов
/ 21 июня 2011

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

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

Ваша главная проблема должна заключаться в проверке того, что список не пуст, таким образом гарантируя, что --it-> end () существует.

...