C++11 异常

C++异常概念

在C++中,异常是程序在执行过程中遇到意外情况或错误时抛出的一种机制。当程序运行过程中发生异常,可以通过抛出异常、捕获异常和处理异常来改变程序的正常执行流程。

  • 抛出异常:在程序中,可以使用关键字 throw 来抛出异常。当程序遇到错误或异常情况时,可以通过抛出异常来中断当前的执行流程,并尝试寻找异常处理的代码块。
  • 捕获异常:在需要处理异常的地方,可以使用 try、catch 块来捕获并处理异常。try 块用于包围可能会抛出异常的代码,而 catch 块则用于捕获并处理异常。当 try 块中的代码抛出异常时,程序的执行流程会跳转到匹配异常类型的 catch 块中进行处理。
  • 处理异常:catch 块用于捕获并处理特定类型的异常。当发生异常时,会进行异常的类型匹配,找到匹配的 catch 块,然后执行该块中的处理逻辑。可以在 catch 块中进行异常处理、恢复正常执行或者再次抛出异常。
//感受异常处理
double Fun(int a, int b)
{
	if (b == 0)
	{
		string Exp = "分母为0";
		throw Exp;
	}
	else
	{
		return (double)a / b;
	}
}

int main()
{
	while (1)
	{
		int a = 0;
		int b = 0;
		cin >> a >> b;
		try
		{
			auto ret = Fun(a, b);
			cout << "运算正常:" << ret << endl;
		}
		catch (const string& Exp)
		{
			cout << Exp << endl;
		}
	}
	return 0;
}

C++11 异常_第1张图片


异常的使用

异常的抛出和匹配原则

  1. 异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪个catch的处理代码
  2. 被选中的处理代码(catch)是调用链中与该对象类型匹配且离抛出异常位置最近的那一个。
  3. 抛出异常对象后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个临时对象,所以会生成一个拷贝对象,这个拷贝的临时对象会在被catch以后销毁。(这里的处理类似于函数的传值返回)
  4. catch(…)可以捕获任意类型的异常,问题是不知道异常错误是什么。
  5. 实际中抛出和捕获的匹配原则有个例外,并不都是类型完全匹配,可以抛出的派生类对象,使用基类捕获。
//解释第二条原则
#include 
#include 

void foo() {
  try {
    throw std::logic_error("Exception in foo()");  // 抛出异常
  }
  catch (std::runtime_error& ex) {
    std::cout << "Caught runtime_error in foo(): " << ex.what() << std::endl;
  }
  catch (std::exception& ex) {
    std::cout << "Caught exception in foo(): " << ex.what() << std::endl;
  }
}

int main() {
  try {
    foo();
  }
  catch (std::runtime_error& ex) {
    std::cout << "Caught runtime_error in main(): " << ex.what() << std::endl;
  }
  catch (...) {
    std::cout << "Caught unknown exception in main()" << std::endl;
  }

  return 0;
}

在函数调用链中异常栈展开匹配原则:

1、首先检查throw本身是否在try块内部,如果是再查找匹配的catch语句。如果有匹配的,则调到catch的地方进行处理。
2、没有匹配的catch则退出当前函数栈,继续在调用函数的栈中进行查找匹配的catch。
3、如果到达main函数的栈,依旧没有匹配的,则终止程序。上述这个沿着调用链查找匹配的catch子句的过程称为栈展开。所以实际中我们最后都要加一个catch(…)捕获任意类型的异常,否则当有异常没捕获,程序就会直接终止。
4、找到匹配的catch子句并处理以后,会继续沿着catch子句后面继续执行。

C++11 异常_第2张图片


自定义异常体系

#include 
class MyException 
{
public:
    MyException(const string& message)
        : m_message(message) 
    {}

    string what() const 
    {
        return m_message;  
    }

private:
    const string m_message;
};

class InvalidDataException : public MyException 
{
public:
    InvalidDataException(const string& message) 
        : MyException(message) 
    {}
};

class DivideByZeroException : public MyException
{
public:
    DivideByZeroException(const string& message) 
        : MyException(message) 
    {}
};

void processData(int data) 
{
    if (data < 0) 
    {
        throw InvalidDataException("无效的数据。不允许使用负数值");
    }
    if (data == 0)
    {
        throw DivideByZeroException("分母为0");
    }

    // Process the data...
    std::cout << "数据已成功处理" << std::endl;
}

int divide(int dividend, int divisor) {
    if (divisor == 0) {
        throw DivideByZeroException("分母为0");
    }
    return dividend / divisor;
}

int main()
{
    while (1)
    {
        try 
        {
            int data;
            cin >> data;;
            processData(data);
        }
        catch (const MyException& ex)   //InvalidDataException
        {
            cout << ex.what() << endl;
        }
        catch (...)
        {
            cout << "未知异常" << endl;
        }
    }
    return 0;
}

C++11 异常_第3张图片
我们自己定义了一个异常父类,使用继承、虚函数重写实现异常处理的多态


你可能感兴趣的:(C++,c++)