之前在刷 leetcode 时用到了异常处理,记录一下。
一般来说 C++ 的库函数调用时,如果发生参数使用不当,或参数超限等,程序会直接抛出异常而终止运行,但这并不是我们想要的结果,我们往往希望当出现异常时,再对异常进行特殊处理进而完善程序,使程序继续执行。
在 leetcode myAtoi() 一题中,要求实现字符串转数字,但是这里的字符串转数字要比 标准库中的 std::stoi()
函数考虑的情况更多!所以直接省懒劲,能用stoi()
转换的直接转换,对于stoi()
不能处理的字符串再进行特殊处理。
源代码片段:
else
res = stoi(str);
这样写的话,显然如果 stoi()
无法转换则程序会直接抛出异常,stoi()
抛出的异常有两种(参见官方文档):
- 若不能进行转换则为
std::invalid_argument
- 若转换值会落在结果类型的范围外,或若底层函数( std::strtol 或 std::strtoll )设置 errno 为 ERANGE 则为
std::out_of_range
else
{
try
{
res = stoi(str);
}
catch (const std::exception& e) // 捕获异常,这里用的是 std::exception,即未指明具体异常类型,适用于只想捕获异常,而不做相应处理的情况
{ // 这时在对异常进行处理
std::cerr << e.what() << endl; // 输出是什么异常
// some code response to this exception
}
}
上面提到 stoi()
会抛出两种异常,我们可以根据这两种异常做相应处理:
else
{
try
{
res = stoi(str);
}
catch (const std::invalid_argument& e) // 捕获 std::invalid_argument 异常
{ // 这时在对异常进行处理
std::cerr << e.what() << endl; // 输出是什么异常
// some code response to this exception,作出处理
}
catch (const std::out_of_range& e) // 捕获 std::out_of_range 异常
{ // 这时在对异常进行处理
std::cerr << e.what() << endl;
// some code response to this exception,作出处理
}
}
try 往往和 catch 搭配使用,catch 可以有多个,但至少要有一个。需要注意的是 try 语句块内声明的变量在块外部无法访问(即使是在 catch 子句内也不行)!
自己编写带异常处理的代码
以除法除以零为例:你可以抛出 C++ 中的标准异常类型(runtime_error 为例)
#include <iostream>
using namespace std;
int main()
{
int a = 2;
int b = 0;
try
{
if (0 == b) // 如果除数为 0 ,抛出 runtime_error 异常,内容为"除零!!!"
throw runtime_error("除零!!!");
cout << a / b << endl;
}
catch(const runtime_error &e)
{
std::cerr << e.what() << '\n'; // 除零!!!
}
return 0;
}
也可以自定义异常类型:
try
{
if (0 == b) // 如果除数为 0 ,抛出 runtime_error 异常,内容为"除零!!!"
throw a; // 直接抛出整数 a
cout << a / b << endl;
}
catch(int e) // 这里用 e 来接收 a 的值
{
std::cerr << e << "不能除以0!" << endl; // 2不能除以0!
}