2010-05-27 3 views
1

Я делаю простую командную строку Hangman.C++ STL: проблема с итераторами строк

void Hangman::printStatus() 
{ 
    cout << "Lives remaining: " << livesRemaining << endl; 
    cout << getFormattedAnswer() << endl; 
} 

string Hangman::getFormattedAnswer() 
{ 
    return getFormattedAnswerFrom(correctAnswer.begin(), correctAnswer.end()); 
} 

string Hangman::getFormattedAnswerFrom(string::const_iterator begin, string::const_iterator end) 
{ 
    return begin == end? "" : displayChar(*begin) + getFormattedAnswerFrom(++begin, end); 
} 

char Hangman::displayChar(const char c) 
{ 
    return c; 
} 

(В конце концов, я изменю это так displayChar() отображает - или символов, если пользователь угадал, но для простоты теперь я просто возвращаюсь все.)

Когда я строй и запустите это из VS 2010, я получаю всплывающее окно:

Ошибка отладки!

xstring Line: 78

Выражение: строка итератор не разыменовываемое

Что я делаю неправильно?

+0

Не могли бы вы попытаться получить трассировку во время отладки, чтобы убедиться, что код вы вывесили причины такого поведения? – jpalecek

+2

Есть ли конкретная причина, по которой вы используете рекурсивную реализацию? Итеративная реализация будет проще. –

+0

@ Джеймс, да, ты прав. Я реализовал его итеративно, и теперь он работает. –

ответ

8

проблема заключается в оценке:

displayChar(*begin) + getFormattedAnswerFrom(++begin, end) 

при выполнении этого стата ление, то очевидно, что ваш компилятор первое приращения begin, возвращая «следующий» begin для использования в качестве первого аргумента getFormattedAnswerFrom и затем разыменования begin для аргумента displayChar.

Когда begin один за end, то begin != end так будет displayChar(*begin) + getFormattedAnswerFrom(++begin, end). Ваш компилятор увеличивает begin, так что теперь begin == end, и разыменован begin.

Смотрите также: Order of evaluation in C++ function parameters

+0

Определяет ли спецификацию C++ порядок оценки подвыражений бинарных операторов или это просто обычное право справа налево, как вы утверждаете? –

+0

+1: Неопределенное поведение, как я могу его пропустить ... – jpalecek

+0

@David: Это UB, по крайней мере, для примитивных типов. Для типов пользователей это не указано, но также может быть неопределенным (я точно не знаю). – jpalecek

0

Если correctAnswer пуст, correctAnswer.begin() будет таким же, как correctAnswer.end(), и не может быть разыскан.

+3

Но разве он не должен немедленно прекращать рекурсию? – jpalecek

+3

У него есть проверка на это. Вы говорите, что даже если begin == end, displayChar (* begin) + getFormattedAnswerFrom (++ begin, end); все еще будут вычислены? – Anthony

+0

@jpalecek: Ах да, это правда. – fbrereto

0

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

Кроме того, я просто немного обеспокоен вашими функциями здесь. Они кажутся очень странными. Почему бы просто не заменить std :: for_each?

Edit @ комментарий:
Если у вас есть C++ 0x, вы можете просто сделать

std::for_each(correctAnswer.begin(), correctAnswer.end(), [this](const char& ref) { 
    std::cout << this->displayChar(ref); 
}); 

В противном случае, вам придется делать то, что выглядит немного как это:

struct helper { 
    Hangman* ptr; 
    void operator()(const char& ref) { 
     std::cout << ptr->displayChar(ref); 
    } 
}; 
helper Helper; 
Helper.ptr = this; 
std::for_each(correctAnswer.begin(), correctAnswer.end(), Helper); 
+0

Можете ли вы показать мне решение, использующее for_each? –

+0

Отредактировано: у вас не должно быть проблем с этим. – Puppy

+0

Интригующий. Можете ли вы объяснить синтаксис верхнего примера? В чем смысл «этого»? –

Смежные вопросы