Итератор для второго и последнего элементов в списке

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

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

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

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

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

Советы? Спасибо заранее

Ответы

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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;
}; 

Ответ 3

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

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

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

Ответ 4

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

for(list<string>::reverse_iterator jt=++(it->rbegin()); jt!=it->rend(); jt++)

Ответ 5

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

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

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

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

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