Я новичок в C++, и я исхожу из сценария Delphi, в котором я смог поймать исключения даже без объявления явного throw
. Посмотрите здесь:
#include<iostream>
#include<exception>
int main() {
try {
int c;
std::cin >> c;
} catch(...) {
std::cerr << "Warning!" << std::endl;
char xz; std::cin >> xz;
return 1;
}
char z; std::cin >> z;
return 0;
}
//I return 1 because UNIX OS cares about this, a return != 0 means that Huston we have a problem
Я видел вокруг, что некоторое исключение (например, деление на ноль) автоматически не зацепилось, поэтому мне нужно создать throw
сам, который наверняка будет обнаружен в моем блоке try-block.
Если вы посмотрите на код выше, когда я впервые введу 6.7
или test
я должен уметь видеть на выходном warning!
, но ничего. Я работаю на компьютере с Windows 10.
Я знаю, что catch(...)
является общим и дает мне уверенность в защите, но почему он не поймал неправильный ввод?
Примечание. Я упомянул Delphi выше, потому что, если вы посмотрите на код ниже, я могу уловить ошибку.
try
a := StrToInt('6.78'); //conversion error [string->double], a is int
ShowMessage('a is ' + a.ToString);
except
on E: Exception do
ShowMessage('Warning! > ' + e.Message);
//^ raises "Warning! > '6.78' is not a valid integer value."
end;
Почему я не могу произвести тот же эффект с C++? Я знаю, что это два разных языка, но сначала я бы сказал, что delphi "обрабатывает" исключения лучше. Например, он автоматически ловит деление на ноль (см. Ниже), в то время как C++ не работает.
//this raises the "Division by zero" error.
a := 8 div StrToInt('0');
Заключение. Итак, вопросы: я правильно объявляю C++ try-catch
? Всегда ли я должен использовать throw
чтобы быть уверенным, что ошибка будет поймана или я могу опустить это несколько раз?
std::cin
не будет бросать, когда пользователь вводит недопустимый тип.
Предполагая, что С++ 11 и выше, поведение выглядит следующим образом:
Если извлечение завершается неудачно, нуль записывается в значение и устанавливается битбита. Если извлечения приводит к слишком большому или слишком маленькому значению, чтобы соответствовать значению, записывается std :: numeric_limits :: max() или std :: numeric_limits :: min() и устанавливается флаг failbit.
из std::basic_istream::operator>>
.
Чтобы проверить, недействителен ли вход, вы должны сделать следующее:
#include <cstdint>
#include <iostream>
std::int32_t main()
{
std::int32_t example;
std::cin >> example;
if (std::cin.fail())
{
std::cout << "Invalid input" << std::endl;
}
}
Или вы также можете сделать это следующим образом:
#include <cstdint>
#include <iostream>
std::int32_t main()
{
std::int32_t example;
if (!(std::cin >> example))
{
std::cout << "Invalid input" << std::endl;
}
}
bool
, например: if (!(std::cin >> example))
.
Как указано в документации, вам нужно установить маску исключений для std::cin
чтобы заставить ее сбрасывать std::ios_base::failure
:
#include <iostream>
int main() {
std::cin.exceptions( std::ios::failbit );
try {
int i = 0;
std::cin >> i;
std::cout << "i=" << i << std::endl;
}
catch(...) {
std::cerr << "error!" << std::endl;
}
return 0;
}
Всегда ли я должен использовать бросок, чтобы быть уверенным, что ошибка будет поймана или я могу опустить это несколько раз?
Да для исключения нужно throw
вызов. Хотя библиотеки могут вызывать throw для вас для условий ошибки (включая стандартный), какое исключение может быть выбрано, и когда должно быть указано в документации.
StrToInt()
имеют явные операторыraise
которые генерируют исключения, когда они сталкиваются с неверными входными данными Delphi RTL также реагирует на сгенерированные системой исключения (нарушение доступа, деление на ноль и т. Д.) И преобразует их в исключения в стиле Delphi. Вот почему вы можете ловить такие вещи, какEAccessViolation
,EDivByZero
и т. Д. C ++ не выполняет такое преобразование, но существуют сторонние библиотеки, которые делают это.