C++异常

简介: C++异常

C++异常


异常是处理程序中的错误。所谓的错误时指程序运行的过程中发生的一些异常事件(如:除零错误,数组下标越界,所要读取的文件不存在,空指针,内存不足等)


C++异常机制相比C语言异常处理的优势:


  • 函数返回值可以忽略,但是异常不可以忽略,并且容易和正常结果混淆;
  • 如果程序出现异常,但是没有被捕获,程序就会终止;


异常语法


代码示例

#include <iostream>
#include <string>
#include <iostream>
using namespace std;
int test01()
{
    throw 0;
    return 0;
}
void test02()
{
    try
    {
        test01();
    }
    catch (int e)
    {
        std::cout << "int exception " << e << std::endl;
    }
    catch (char e)
    {
        std::cout << "char exception " << e << std::endl;
    }
    catch (...)
    {
        std::cout << "normal exception " << std::endl;
    }
}
int main(int argc, char* argv[])
{
    test02();
    return 0;
}


栈解旋


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


示例代码

#include <iostream>
#include <string>
#include <iostream>
using namespace std;
class Person
{
public:
    Person(string name1)
    {
        name = name1;
        cout << "Person " << name << endl;
    }
    ~Person()
    {
        cout << "~Person" << name << endl;
    }
    string name;
};
void test()
{
    try {
        Person p("1");
        Person p1("2");
        Person p2("3");
        throw 10;
    }
    catch (...)
    {
        cout << "exception" << endl;
    }
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


noexcept


  • 为了加强程序可读性,可以在函数声明中指定是否可以抛出异常。


例如:void func() noexcept(true);表示函数函数无法抛出异常, 后面的true可省略

例如:void func() noexcept(false);表示函数函数可能抛出异常


代码示例

#include <iostream>
#include <string>
#include <iostream>
using namespace std;
void test() noexcept(false)
{
    // throw 10;
}
void test01() noexcept(true)
{
    throw 10;
}
int main(int argc, char* argv[])
{
    try {
        test();
        test01();
    }
    catch (...)
    {
        cout << "exception" << endl;
    }
    return 0;
}


异常的声明周期


throw 的异常是有类型的,可以是数字、字符串、类对象。throw的异常是有类型的,catch需要严格匹配异常的类型。


示例代码

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

class MyException
{
public:
    MyException()
    {
        cout << "MyException" << endl;
    }
    MyException(const MyException &other)
    {
        cout << "MyException2" << endl;
    }
    ~MyException()
    {
        cout << "~MyException" << endl;
    }
};
int test1()
{
    try {
        throw MyException();
    }
    catch (MyException e)
    {
        cout << "exception" << endl;
    }
    return 0;
}
int test2()
{
    try {
        throw MyException();
    }
    catch (const MyException &e)
    {
        cout << "exception" << endl;
    }
    return 0;
}
int test3()
{
    try {
        throw new MyException();
    }
    catch (MyException *e)
    {
        cout << "exception" << endl;
        delete e;
        e = nullptr;
    }
    return 0;
}
int test4()
{
    try {
        MyException ob;
        throw ob;
    }
    catch (MyException &e)
    {
        cout << "exception" << endl;
    }
    return 0;
}
int test5()
{
    try {
        throw MyException();
    }
    catch (MyException &e)
    {
        cout << "exception" << endl;
    }
    return 0;
}
int main(int argc, char* argv[])
{
    test5();
    return 0;
}

注意: 抛出指针的时候记得析构, 推荐test5()的这种方式,可以提高效率。


异常的多态使用


与正常多态使用无差别


代码示例

#include <iostream>
#include <string>
#include <iostream>
using namespace std;
class BaseException
{
public:
    virtual void printLog() = 0;
};
class DeriveException1 : public BaseException
{
public:
    void printLog() override
    {
        cout << "exception1" << endl;
    }
};
void test()
{
    try {
        throw DeriveException1();
    }
    catch (BaseException &e)
    {
        e.printLog();
    }
}

int main(int argc, char* argv[])
{
    test();
    return 0;
}


C++标准异常库


标准库中有很多的异常类,它们是通过类继承组织起来的。


exception 类的直接派生类:

异常名称 说 明
logic_error 逻辑错误。
runtime_error 运行时错误。
bad_alloc 使用 new 或 new[ ] 分配内存失败时抛出的异常。
bad_typeid 使用 typeid 操作一个 NULL 指针,而且该指针是带有虚函数的类,这时抛出 bad_typeid 异常。
bad_cast 使用 dynamic_cast 转换失败时抛出的异常。
ios_base::failure io 过程中出现的异常。
bad_exception 这是个特殊的异常,如果函数的异常列表里声明了 bad_exception 异常,当函数内部抛出了异常列表中没有的异常时,如果调用的 unexpected() 函数中抛出了异常,不论什么类型,都会被替换为 bad_exception 类型。


logic_error 的派生类:

异常名称 说 明
length_error 试图生成一个超出该类型最大长度的对象时抛出该异常,例如 vector 的 resize 操作。
domain_error 参数的值域错误,主要用在数学函数中,例如使用一个负值调用只能操作非负数的函数。
out_of_range 超出有效范围。
invalid_argument 参数不合适。在标准库中,当利用string对象构造 bitset 时,而 string 中的字符不是 0 或1 的时候,抛出该异常。


runtime_error 的派生类:

异常名称 说 明
range_error 计算结果超出了有意义的值域范围。
overflow_error 算术计算上溢。
underflow_error 算术计算下溢。


代码示例

#include <iostream>
#include <string>
#include <iostream>
using namespace std;
void test(int i)
{
    try {
        if(i > 50)
        {
            throw out_of_range("越界");
        }
        else
        {
            throw exception("exception");
        }
    }
    catch (exception &e)
    {
        cout << e.what() << endl;
    }
}
int main(int argc, char* argv[])
{
    test(60);
    return 0;
}


重写自己的异常


使用继承实现一个自己的异常(我这里是一个简单的实现)


示例代码

#include <iostream>
#include <string>
#include <iostream>
using namespace std;
class MyException : public exception
{
public:
    MyException(const char *data) noexcept
            : exception(data)
    {
    }
};
void test(int i)
{
    try {
        throw MyException("my exception");
    }
    catch (exception &e)
    {
        cout << e.what() << endl;
    }
}
int main(int argc, char* argv[])
{
    test(60);
    return 0;
}
目录
相关文章
|
6月前
|
算法 编译器 C语言
【C++ 异常】C++ 标准库异常类及其应用
【C++ 异常】C++ 标准库异常类及其应用
75 0
|
6月前
|
C++
C++ 捕获所有异常并拿到错误原因的方法
C++ 捕获所有异常并拿到错误原因的方法
171 0
|
6月前
|
安全 算法 C++
【C++ 异常 】深入了解C++ 异常机制中的 terminate()处理 避免不必要的错误(三)
【C++ 异常 】深入了解C++ 异常机制中的 terminate()处理 避免不必要的错误
125 0
|
6月前
|
存储 安全 算法
【C/C++ 关键字 函数说明符 】C++ noexcept 关键字(指定某个函数不抛出异常)
【C/C++ 关键字 函数说明符 】C++ noexcept 关键字(指定某个函数不抛出异常)
76 0
|
6月前
|
SQL 安全 程序员
C++:异常
C++:异常
54 7
|
6月前
|
小程序 编译器 Linux
C++ 异常原理:以一个小程序为例
作者在调查某个 bug 时涉及到 C++ 异常,借此机会以本文把 C++ 异常机制梳理清楚供大家参考。
|
6月前
|
安全 Java 程序员
【C++】异常 -- 详解
【C++】异常 -- 详解
|
4月前
|
C++
C++ 异常机制问题之捕获异常的问题如何解决
C++ 异常机制问题之捕获异常的问题如何解决
|
4月前
|
安全 Java 程序员
【C++11】异常知多少
【C++11】异常知多少
39 7
|
6月前
|
缓存 安全 Java
从C语言到C++_35(异常)C++异常的使用+异常体系+异常优缺点(下)
从C语言到C++_35(异常)C++异常的使用+异常体系+异常优缺点
49 7