函数抛出异常学习

转自: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!
View Code
  • 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。
View Code
  • bad_alloc:在用 new 运算符进行动态内存分配时,如果没有足够的内存,则会引发此异常。
  • out_of_range:用 vector 或 string 的 at 成员函数根据下标访问元素时,如果下标越界,则会拋出此异常。

 

posted @ 2023-07-26 21:48  lypbendlf  阅读(150)  评论(0编辑  收藏  举报