C++异常

此课件及源代码来自B站up主:码农论坛,该文章仅作为本人学习笔记使用。

一、异常的语法

1)捕获全部的异常

    try
    {
        // 可能抛出异常的代码。
        // throw 异常对象;
    }

    catch (...)
    {
        // 不管什么异常,都在这里统一处理。
    }

2)捕获指定的异常

    try
    {
        // 可能抛出异常的代码。
        // throw 异常对象;
    }

    catch (exception1 e)
    {
        // 发生exception1异常时的处理代码。
    }
    catch (exception2 e)
    {
       // 发生exception2异常时的处理代码。
    }

try语句块中,如果没有发生异常,执行完try语句块中的代码后,将继续执行try语句块之后的代码;如果发生了异常,用throw抛出异常对象,异常对象的类型决定了应该匹配到哪个catch语句块,如果没有匹配到catch语句块,程序将调用abort()函数中止。

如果try语句块中用throw抛出异常对象,并且匹配到了catch语句块,执行完catch语句块中的代码后,将继续执行catch语句块之后的代码,不会回到try语句块中。

如果程序中的异常没有被捕获,程序将异常中止。

示例:

#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
    try
    {
        // 可能抛出异常的代码。
        int ii = 0;
        cout << "你是一只什么鸟?(1-傻傻鸟;2-小小鸟)";
        cin >> ii;

        if (ii==1)  throw "不好,有人说我是一只傻傻鸟。";            // throw抛出const char *类型的异常。
        if (ii==2)  throw ii;                                                             // throw抛出int类型的异常。
        if (ii==3)  throw string("不好,有人说我是一只傻傻鸟。"); // throw抛出string类型的异常。

        cout << "我不是一只傻傻鸟,哦耶。\n";
    }

    catch (int ii)
    {
        cout << "异常的类型是int=" << ii << endl;
    }
    catch (const char* ss)
    {
        cout << "异常的类型是const char *=" << ss << endl;
    }
    catch (string str)
    {
        cout << "异常的类型是string=" << str << endl;
    }
    //catch (...)  // 不管什么异常,都在这里处理。
    //{
    //    cout << "捕获到异常,具体没管是什么异常。\n";
    //}
    cout << "程序继续运行......\n";   // 执行完try ... catch ...后,将继续执行程序中其它的代码。
}

二、栈解旋

异常被抛出后,从进入try语句块开始,到异常被抛出之前,这期间在上构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反。这一过程称为栈的解旋。

也就是在执行throw前,在try执行期间构造的所有对象被自动析构后,才会进入catch匹配。

上构造的对象肿么办?也是先构造的后析构。

三、异常规范

C++98标准提出了异常规范,目的是为了让使用者知道函数可能会引发哪些异常。

void func1() throw(A, B, C);     // 表示该函数可能会抛出A、B、C类型的异常。

void func2() throw();           // 表示该函数不会抛出异常。

void func3();                  // 该函数不符合C++98的异常规范。

C++11标准弃用了异常规范,使用新增的关键字noexcept指出函数不会引发异常。

void func4() noexcept;         // 该函数不会抛出异常。

在实际开发中,大部分程序员懒得在函数后面加noexcept,弃用异常已是共识,没必要多此一举。

关键字noexcept也可以用作运算符,判断表达试(操作数)是否可能引发异常;如果表达式可能引发异常,则返回false,否则返回true。

四、C++标准库异常

      

五、重点关注的异常

1)std::bad_alloc

如果内存不足,调用new会产生异常,导致程序中止;如果在new关键字后面加(std::nothrow)选项,则返回nullptr,不会产生异常。

示例:

#include <iostream>
using namespace std;

int main()
{
      try {
            // 如果分配内存失败,会抛出异常。
            //double* ptr = new double[100000000000]; 
            // 如果分配内存失败,将返回nullptr,不会抛出异常。
            double* ptr = new (std::nothrow) double[100000000000]; 

            if (ptr == nullptr) cout << "ptr is null.\n";
      }

      catch (bad_alloc& e)
      {
            cout << "catch bad_alloc.\n";
      }
}

2)std::bad_cast

dynamic_cast可以用于引用,但是,C++没有与空指针对应的引用值,如果转换请求不正确,会出现std::bad_cast异常。

3)std::bad_typeid

假设有表达式typeid(*ptr),当ptr是空指针时,如果ptr是多态的类型,将引发std::bad_typeid异常。

六、逻辑错误异常

程序的逻辑错误产生的异常std::logic_error,通过合理的编程可以避免。

1)std::out_of_range

Defines a type of object to be thrown as exception. It reports errors that are consequence of attempt to access elements out of defined range.

It may be thrown by the member functions of std::bitset and std::basic_string, by std::stoi and std::stod families of functions, and by the bounds-checked member access functions (e.g. std::vector::at and std::map::at).

2)std::length_error

Defines a type of object to be thrown as exception. It reports errors that result from attempts to exceed implementation defined length limits for some object.

This exception is thrown by member functions of std::basic_string and std::vector::reserve.

3)std::domain_error

Defines a type of object to be thrown as exception. It may be used by the implementation to report domain errors, that is, situations where the inputs are outside of the domain on which an operation is defined.

The standard library components do not throw this exception (mathematical functions report domain errors as specified in math_errhandling). Third-party libraries, however, use this. For example, boost.math throws std::domain_error if boost::math::policies::throw_on_error is enabled (the default setting).

4)std::invalid_argument

Defines a type of object to be thrown as exception. It reports errors that arise because an argument value has not been accepted.

This exception is thrown by std::bitset::bitset, and the std::stoi and std::stof families of functions.

示例1:

#include <iostream>
#include <vector> 
using namespace std;

int main()
{
      try{
            vector<int> vv = { 1,2,3 };  // 容器vv中只有三个元素。
            vv.at(3) = 5;                        // 将引发out_of_range异常。
      }
      catch (out_of_range) {
            cout << "出现了out_of_range异常。\n";
      }
}

示例2:

#include <stdexcept>
#include <iostream>
#include <string>
using namespace std;

int main()
{
      string str = "123";  // 不会抛出异常。  
      //string str = "";     // 将抛出Invalid_argument异常。
      //string str = "253647586946334221002101";  // 将抛出out_of_range异常。

      try {
            int x = stoi(str);        // 把string字符串转换为整数。
            cout << "x=" << x << endl;
      }

      catch (invalid_argument&) {
            cout << " invalid_argument. \n";
      }
      catch (out_of_range&) {
            cout << " out of range. \n";
      }
      catch (...) {
            cout << " something else…" << endl;
      }
}

七、其它异常

1)std::range_error

Defines a type of object to be thrown as exception. It can be used to report range errors (that is, situations where a result of a computation cannot be represented by the destination type).

The only standard library components that throw this exception are std::wstring_convert::from_bytes and std::wstring_convert::to_bytes.

The mathematical functions in the standard library components do not throw this exception (mathematical functions report range errors as specified in math_errhandling).

2)std::overflow_error    

Defines a type of object to be thrown as exception. It can be used to report arithmetic overflow errors (that is, situations where a result of a computation is too large for the destination type)

The only standard library components that throw this exception are std::bitset::to_ulong and std::bitset::to_ullong.

The mathematical functions of the standard library components do not throw this exception (mathematical functions report overflow errors as specified in math_errhandling). Third-party libraries, however, use this. For example, boost.math throws std::overflow_error if boost::math::policies::throw_on_error is enabled (the default setting).

3)std::underflow_error  

Defines a type of object to be thrown as exception. It may be used to report arithmetic underflow errors (that is, situations where the result of a computation is a subnormal floating-point value)

The standard library components do not throw this exception (mathematical functions report underflow errors as specified in math_errhandling). Third-party libraries, however, use this. For example, boost.math throws std::underflow_error if boost::math::policies::throw_on_error is enabled (the default setting

4)ios_base::failure

这个异常,程序员不主动找它就没事。

示例:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    fstream file;
    file.exceptions(ios::failbit);    // 设置如果出现ios::failbit,就引发异常。

    try
    {
        file.open("rm.txt", ios_base::in);  // 如果打开的文件不存在,就会引发异常。
    }

    catch (ios_base::failure f)
    {
        cout << caught an exception: " << f.what() << endl;
    }
}

5)std::bad_exception

This is a special type of exception specifically designed to be listed in the dynamic-exception-specifier of a function (i.e., in its throw specifier).

If a function with bad_exception listed in its dynamic-exception-specifier throws an exception not listed in it and unexpected rethrows it (or throws any other exception also not in the dynamic-exception-specifier), a bad_exception is automatically thrown.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值