2012-05-08 3 views
1

Я знаю, что это очень глупый вопрос, но я хотел прояснить это.C++ iterator loop vs index loop

Скажем, у меня есть одна строка вектор выглядит,

vector<int> vnTemp; // suppose this vector has {1,2,3,4,5} 
vector<int>::iterator vn_it; 

//Now, I want to print out only 1 to 4. 
for(int i=0; i<4; ++i) 
    cout << vnTemp[i] << endl; 

Довольно просто. но что мне делать, когда я хочу распечатать эквивалентный результат с помощью итератора? для exmample,

// .. continuing from the code above 
for(vn_it = vnTemp.begin(); vn_it != vnTemp.end()-1; ++vn_it) 
    cout << *it << endl; 

Конечно, vnTemp.end()-1 приведет к ошибке, так как это указатель.

Что такое эквивалент цикла в этом случае? и есть ли разница в производительности, когда они оба скомпилированы в оптимизированном режиме (-o)?


Edit:

Я только понял, что это на самом деле работает с vector. Проблема произошло, когда я использовал boost::tokenizer Кодекса, как это:

typedef boost::tokenizer<boost::char_separator<char> > tokenizer; 

boost::char_separator<char> sep("_"); 
tokenizer::iterator tok_it; 

tokenizer tokens(strLine, sep); //strLine is some string line 
for(tok_it=tokens.begin(); tok_it != tokens.end(); ++tok_it){ 
... } 

Это был исходный код, и ошибка возникает, когда я пытаюсь сказать tokens.end()-1 в цикле.

Есть ли способ решить эту проблему? Извините за двусмысленность.

+4

Это должно работать. Итератор реализует 'operator-'. Кроме того, итераторы - это не просто указатели. Например, 'std :: list' сохраняет свои элементы в несмежной памяти. – chris

+2

Я бы сказал, что ваша проблема несколько надуманна. Реальные проблемы обычно относятся либо к целому контейнеру, либо к каким-либо другим выборам, которые * могут быть написаны очень хорошо с помощью итераторов (например, 'remove_if' или' find'), а итераторы - действительно более подходящий способ рассказать о коллекциях чем индексы. –

+0

Поддержка ускорения итераторов вперед, двунаправленные итераторы поддерживают приращение и уменьшение, а также итераторы с произвольным доступом поддерживают как арифметику, так и «begin() + 4' ... vector использует итераторы произвольного доступа, поэтому у вас есть параметры. Я считаю, что 'boost :: tokenizer' по умолчанию' std :: string :: const_iterator' – AJG85

ответ

3

boost::tokenizer обеспечивает только передний итератор; что означает, что вы не можете вычесть из итератора токенизатора. Если вы хотите, чтобы ваш цикл не обрабатывал последний токен, вам придется «искать вперед», прежде чем обрабатывать токен, в котором вы находитесь. Что-то вроде этого

tokenizer tokens(strLine, sep); //strLine is some string line 
tok_it = tokens.begin(); 
if(tok_it!=tokens.end()) 
{ 
    ++tok_it; 
    for(auto last_tok = tokens.begin(); tok_it != tokens.end(); ++tok_it){ 
     // Process last_tok here 
     . . . 
     last_tok = tok_it;  
    } 
} 

Edit: Альтернативный подход будет копировать маркеры в контейнер с более гибкими итераторов:

std::vector<std::string> resultingTokens(tokens.begin(), tokens.end()); 
for(auto tok=resultingTokens.begin(); tok!=resultingTokens.end()-1; ++tok) 
{ 
    // whatever 
} 
+0

Этот ответ, по сути, правильный, но ему нужна небольшая очистка: '+ 1' все еще не будет работать на итераторах вперед - вы можете использовать только оператор инкремента:' ++ '. Кроме того, правильнее сказать, что * в лучшем случае * boost :: tokenizer' будет производить итераторы вперед. Например, если базовый контейнер является потоком, 'boost :: tokenizer' будет создавать итераторы ввода, которые немного более ограничены. –

+0

Ooops. Вы правы. Спасибо @Michael – zdan

+0

Что делать, если я хочу установить размер шага? скажем 2?Могу ли я писать, как, '++ (++ tok_it)'? – devEvan