Итератор для второго и последнего элементов в списке
В настоящее время для цикла:
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()