Вот код, который вы можете использовать, чтобы убедиться, что вы также отклоняете такие вещи, как
42crap
Где после номера идут нечисловые символы. Если вы прочитали всю строку, а затем проанализировали ее и выполнили соответствующие действия, возможно, вам потребуется изменить способ работы вашей программы. Если ваша программа до сих пор считывает ваш номер из разных мест, вам нужно поместить одно центральное место, которое анализирует одну строку ввода и принимает решение о действии. Но, возможно, это тоже хорошо - так что вы могли бы улучшить читаемость кода, разделив вещи так: I nput - P rocessing - O utput
В любом случае, вот как вы можете отклонить число-номер выше. Прочитайте строку в строку, а затем проанализируйте ее с помощью stringstream
:
std::string getline() {
std::string str;
std::getline(std::cin, str);
return str;
}
int choice;
std::istringstream iss(getline());
iss >> choice >> std::ws;
if(iss.fail() || !iss.eof()) {
// handle failure
}
Съедает все оставшиеся пробелы. Когда он достигает конца файла в потоке строки при чтении целого или конечного пробела, он устанавливает бит eof, и мы проверяем это. Если ему не удалось прочитать какое-либо целое число, то будет установлен бит сбоя или сбой.
Более ранние версии этого ответа использовали std::cin
напрямую - но std::ws
не будет хорошо работать вместе с std::cin
, подключенным к терминалу (вместо этого он будет блокировать ожидание ввода пользователем чего-либо), поэтому мы используем stringstream
для чтения целого числа.
Отвечая на некоторые ваши вопросы:
Вопрос: 1. Использование блока try catch. Это не сработало. Я думаю, это потому, что исключение не вызвано из-за неверного ввода.
Ответ: Ну, вы можете указать потоку генерировать исключения, когда вы что-то читаете. Вы используете функцию istream::exceptions
, которая сообщает, для какого типа ошибки вы хотите создать исключение:
iss.exceptions(ios_base::failbit);
Я никогда не использовал его. Если вы сделаете это на std::cin
, вам нужно будет помнить, чтобы восстановить флаги для других читателей, которые полагаются на то, что они не выбрасывают. Найти способ проще - просто использовать функции fail , bad , чтобы запросить состояние потока.
Вопрос: 2. Я попробовал if(!cin){ //Do Something }
, который тоже не работал. Я еще не понял этого.
Ответ: Это может быть связано с тем, что вы дали ему что-то вроде "42crap". Для потока это полностью допустимый ввод при выполнении извлечения в целое число.
Вопрос: 3. В-третьих, я попытался ввести строку фиксированной длины, а затем проанализировать ее. Я бы использовал atoi (). Являются ли эти стандарты совместимыми и портативными? Должен ли я написать свою собственную функцию синтаксического анализа?
Ответ: Atoi соответствует стандарту. Но это не хорошо, когда вы хотите проверить на наличие ошибок. В отличие от других функций, проверка ошибок не производится. Если у вас есть строка и вы хотите проверить, содержит ли она число, сделайте это, как в приведенном выше исходном коде.
Существуют C-подобные функции, которые могут читать непосредственно из C-строки. Они существуют для взаимодействия со старым, унаследованным кодом и написания быстродействующего кода. Следует избегать их в программах, потому что они работают довольно низкоуровнево и требуют использования сырых голых указателей. По своей природе они не могут быть улучшены для работы с пользовательскими типами. В частности, речь идет о функции "strtol" (строка-в-long), которая в основном является atoi с проверкой ошибок и способностью работать с другими базами (например, hex).
Вопрос: 4. Если я напишу класс, который использует cin, но динамически выполняет этот вид обнаружения ошибок, возможно, путем определения типа входной переменной во время выполнения, будет ли у него слишком много накладных расходов? Это вообще возможно?
Ответ: Как правило, здесь вам не нужно слишком много заботиться о накладных расходах (если вы имеете в виду накладные расходы времени выполнения). Но это зависит конкретно от того, где вы используете этот класс. Этот вопрос будет очень важен, если вы пишете высокопроизводительную систему, которая обрабатывает ввод и должна иметь высокий уровень. Но если вам нужно прочитать ввод из терминала или из файла, вы уже видите, к чему это сводится: ожидание ввода пользователем чего-то занимает очень много времени, вам больше не нужно следить за затратами времени выполнения на этом этапе. масштаб.
Если вы имеете в виду издержки кода - это зависит от того, как реализован код. Вам нужно будет отсканировать прочитанную вами строку - содержит ли она число или нет, является ли какая-либо произвольная строка. В зависимости от того, что вы хотите отсканировать (может быть, у вас есть ввод даты или формат времени). Ваш код может стать произвольно сложным. Для простых вещей, таких как классификация между числами или нет, я думаю, что вы можете избежать небольшого количества кода.