函数抛出异常学习
转自:https://blog.csdn.net/u014694994/article/details/79074566
1、例子
stoi当字符串不符合规范时,会抛出异常。
#include <stdexcept> #include <iostream> #include <string> using namespace std; int main() { std::string y = "253647586946334221002101219955219971002"; int x; try { x = stoi(y); } catch (std::invalid_argument&){ // if no conversion could be performed cout << "Invalid_argument" << endl; } catch (std::out_of_range&){ // if the converted value would fall out of the range of the result type // or if the underlying function (std::strtol or std::strtoull) sets errno // to ERANGE. cout << "Out of range" << endl; } catch (...) { // everything else cout << "Something else" << endl; } return 0; }
运行之后输出:Out of range。说明stoi函数抛出异常,并被捕获。它可能会抛出std::invalid_argument和std::out_of_range异常。
当y中包含字母无法转换为数字时,会抛出std::out_of_range异常,打印结果为:Invalid_argument。(已测试)。如果未找到可用的 catch 块,则调用 std::terminate
并且程序会退出。异常会向上一层层抛出,如果一层层的函数都不处理异常,异常最终会被拋给最外层的 main 函数。main 函数应该处理异常。如果main函数也不处理异常,那么程序就会立即异常地中止。
https://en.cppreference.com/w/cpp/string/basic_string/stol
如果没有try-catch结构捕获异常会发生什么呢?如下:
-> % ./Demo libc++abi: terminating with uncaught exception of type std::out_of_range: stoi: out of range [1] 31182 abort ./Demo
会发生coredump,程序异常退出。
strtol不会抛出异常,那么抛出异常和不抛出异常究竟有什么区别?比较浅显的理解就是抛出异常的函数必须要用try-catch来捕获异常才行,不抛出异常的要用返回参数或传参再判断函数是否成功。
2、异常与性能
如果未引发异常,则异常机制的性能开销极低。 如果引发异常,则堆栈遍历和展开的开销与函数调用的开销大致相当。 进入 try
块后,需要使用额外的数据结构来跟踪调用堆栈,如果引发异常,则还需要使用额外的指令来展开堆栈。(https://learn.microsoft.com/zh-cn/cpp/cpp/errors-and-exception-handling-modern-cpp?view=msvc-170)
https://www.cnblogs.com/zhyg6516/archive/2011/03/08/1977007.html,析构函数中不要抛出异常,大概是因为处理完catch完后就不知道返回到哪里。
3、标准异常类
https://zhuanlan.zhihu.com/p/604192134
- bad_typeid:此类型的异常在应用 typeid 运算符到多态类型的空指针值时抛出。
#include <iostream> #include <typeinfo> struct S { // 类型必须是多态 virtual void f(); }; int main() { S* p = nullptr; try { std::cout << typeid(*p).name() << '\n'; } catch(const std::bad_typeid& e) { std::cout << e.what() << '\n'; } } //输出: Attempted a typeid of NULL pointer!
- bad_cast:在用 dynamic_cast 进行从多态基类对象(或引用)到派生类的引用的强制类型转换时,如果转换是不安全的,则会拋出此异常。如果目标类型是指针,且不安全的话,目标指针会为空,但不会抛出异常。https://en.cppreference.com/w/cpp/language/dynamic_cast
#include <iostream> #include <stdexcept> using namespace std; class Base { virtual void func() {} }; class Derived : public Base { public: void Print() {} }; void PrintObj(Base & b) { try { Derived & rd = dynamic_cast <Derived &>(b); //此转换若不安全,会拋出 bad_cast 异常 rd.Print(); } catch (bad_cast & e) { cerr << e.what() << endl; } } int main() { Base b;//上面的类型是base,不是Derived,所以转换是不安全的 PrintObj(b); return 0; } //输出: std::bad_cast //在 PrintObj 函数中,通过 dynamic_cast 检测 b 是否引用的是一个 Derived 对象,如果是,就调用其 Print 成员函数;如果不是,就拋出异常,不会调用 Derived::Print。
- bad_alloc:在用 new 运算符进行动态内存分配时,如果没有足够的内存,则会引发此异常。
- out_of_range:用 vector 或 string 的 at 成员函数根据下标访问元素时,如果下标越界,则会拋出此异常。