C/C++ - 异常处理

目录

错误处理

异常处理

异常传播

异常规划

标准异常

自定异常


错误处理

  • 在C语言中,错误通常通过函数的返回值来表示。

  • 错误返回值

    • 对于能返回特殊值(如NULL或负值)的函数,在调用时检查这些值来处理错误。
    cpp 复制代码
    #include <stdio.h>
    #include <stdlib.h>
    
    #define DIV_RET_SUCCESS 1
    #define DIV_RET_FAILED  0
    
    //C语言中通过函数返回值来判断执行成功与否
    int myDiv(int num1, int num2, int* nRet)
    {
    	if (num2 == 0)
    	{
    		*nRet - 0;
    		return DIV_RET_FAILED;
    	}
    
    	*nRet = num1 / num2;
    	return DIV_RET_SUCCESS;
    }
    
    int main()
    {
    	int ret = 0;
    	if (myDiv(10, 2, &ret) == DIV_RET_SUCCESS)
    	{
    		printf("%d \r\n", ret);
    	}
    
    	return 0;
    }
  • 错误码全局变量

    • 如 errno,这是一个全局变量,很多标准库函数在出错时会设置这个变量为相应的错误码。
    cpp 复制代码
    #pragma warning(disable:4996)
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    
    int main()
    {
    	FILE* pFile = NULL;
    	pFile = fopen("0xCC.txt", "r");
    	if (pFile == NULL)
    	{
    		printf("ErrorCode -> %d \r\n", errno);
    		printf("ErrorMesg -> %s \r\n", strerror(errno));
    		perror("fopen");
    	}
    
    	return 0;
    }
  • 宏定义

    • 通过宏定义可以创建简单的错误处理代码块,这个方法提供了一种快速插入常用错误处理程序代码的方式。
    cpp 复制代码
    #include <stdio.h>
    #include <stdlib.h>
    #define HANDLE_ERROR(msg) \
        do { \
            perror(msg); \
            exit(EXIT_FAILURE); \
        } while(0)
    int main() 
    {
        FILE *fp = fopen("file.txt", "r");
        if (!fp) 
    	{
            HANDLE_ERROR("Error opening file");
        }
        // 其余代码...
        fclose(fp);
        return 0;
    }

异常处理

  • throw:当问题发生时,程序会抛出一个异常。这是通过 throw​​ 关键字完成的,后面跟着要抛出的异常对象。

    cpp 复制代码
    throw ErrorCode
    throw "Erroe"
  • try:try​​ 块内的代码是可能产生异常的代码,当其中的代码抛出一个异常时,执行流会跳转到匹配的 catch​​ 块。

  • catch:catch​​ 块会捕获异常,并包含如何处理这些异常的代码。

    cpp 复制代码
    try
    {
    	//可能抛出异常的代码
    }
    catch(ExceptionType var)	//根据异常类型捕获
    {
    	//处理匹配异常类型
    }
    catch(ExceptionType var)	//根据异常类型捕获
    {
    	//处理匹配异常类型
    }
  • 示例代码

    cpp 复制代码
    #include <iostream>
    
    int AllocMem()
    {
    	//可能会抛出异常的代码放在try语句块内
    	try
    	{
    		//throw 'A';
    		long long* p = new long long[0xFFFFFFF];
    		//thorw bad_allocation
    	}
    	catch (int exception)
    	{
    		std::cout << exception << std::endl;
    	}
    	catch (char exception)
    	{
    		std::cout << exception << std::endl;
    	}
    	catch (std::exception exception)
    	{
    		std::cout << exception.what() << std::endl;
    	}
    
    }
    
    int main()
    {
    	AllocMem();
    
    
    	return 0;
    }

异常传播

  • C++异常传播(Exception Propagation)是指在程序中如果一个函数内发生了异常,而该异常没有在该函数内得到处理,则该异常会被传递到函数调用者处,如果调用者也不处理,则继续传递,这样一直到最顶层调用者。如果最顶层调用者也没有处理异常,则程序可能崩溃。

    • 如果try块内的代码抛出了异常,控制流会跳到第一个匹配的catch块。
    • 如果在当前函数中没有匹配的catch块,异常会被传递给调用该函数的函数,并在那里寻找匹配的catch块。
    • 如果在任一函数中都找不到匹配的catch块,程序将调用terminate()结束程序。
    cpp 复制代码
    #include <iostream>
    
    void Fun3()
    {
    	throw 0xCC;
    }
    
    void Fun2()
    {
    	try
    	{
    		Fun3();
    	}
    	catch (char exception)
    	{
    		std::cout << exception << std::endl;
    	}
    
    }
    
    void Fun1()
    {
    	try
    	{
    		Fun2();
    	}
    	catch (float exception)
    	{
    		std::cout << "Fun1 Exception" << std::endl;
    	}
    
    }
    
    int main()
    {
    	try
    	{
    		Fun1();
    	}
    	catch (...)
    	{
    		std::cout << "Main Exception" << std::endl;
    	}
    
    	return 0;
    }

异常规划

  • 异常规范(exception specification)是C++中的一种功能,它允许开发者指明一个函数可能抛出哪些异常。
  • 自从C++11起,异常规范已经不再被推荐使用,取而代之的是noexcept关键字。
  • void someFunction() throw(int, char); // 只能抛出int型和char型异常
  • void someFunction() noexcept; // 不会抛出异常
cpp 复制代码
#include <iostream>
#include <vector>

//该函数不会抛出任何异常
void Fun1() throw()
{

}

void Fun2() noexcept
{

}

void Fun3() throw(int)
{

}

void Fun4() throw(char)
{

}

void Fun5() throw(char, int)
{

}

int main()
{
	try
	{
		Fun3();
	}
	catch (int exception)
	{
		std::cout << exception << std::endl;
	}

	try
	{
		Fun4();
	}
	catch (char exception)
	{
		std::cout << exception << std::endl;
	}

	try
	{
		Fun5();
	}
	catch (char exception)
	{
		std::cout << exception << std::endl;
	}
	catch (int exception)
	{
		std::cout << exception << std::endl;
	}

	return 0;
}

标准异常

  • std::exception 是各种标准异常类的基础,提供了一个异常层次结构。
  • ​std::logic_error​​

    • 逻辑错误表示程序的逻辑不当导致的问题,这通常是可以预防的错误。
    • std::domain_error: 当一个数学函数接收到一个不在其定义域内的参数时抛出。
    • std::invalid_argument: 当传递给函数的参数无效时抛出。
    • std::length_error: 当创建过大的 std::string 或者 std::vector 时抛出。
    • std::out_of_range: 当通过 at 访问 std::vector 或 std::string 而下标超出范围时抛出。
  • std::runtime_error​​

    • 运行时错误,表示在程序运行时发现的错误,通常是难以预防的。
    • std::overflow_error: 当算术运算超过表示范围时抛出。
    • std::underflow_error: 当算术运算结果在正确的表示范围内,但非正规化时抛出。
    • std::range_error: 当计算的结果不在可表示的范围内时抛出。
    • std::system_error: 用于报告系统错误的异常。
  • std::bad_alloc​​

    当动态内存分配失败时(如 new​​ 表达式),std::bad_alloc​​ 被抛出。

  • std::bad_cast​​​

    使用动态转换 (dynamic_cast​​) 转换到不兼容的类型时,抛出 std::bad_cast​​。

  • std::bad_typeid​​​

    当使用类型信息功能(如 typeid​​ 操作符)并且操作的对象是未定义类型时,抛出 std::bad_typeid​​ 异常。

  • ​std::bad_function_call​​​

    当调用一个空的 std::function​​ 对象时,抛出 std::bad_function_call​​ 异常。

cpp 复制代码
#include <iostream>

int main()
{
	try
	{
		long long* p = new long long[0xFFFFFFF];
	}
	catch (const std::exception& e)
	{
		std::cout << e.what() << std::endl;
	}

	return 0;
}

自定异常

cpp 复制代码
#include <iostream>

class myException :public std::exception
{
public:
	myException(std::string message): m_Message(message){}

	virtual const char* what() const
	{
		return m_Message.c_str();
	}


private:
	std::string m_Message;
};

int main()
{
	try
	{
		myException obj("cc exception");
		throw obj;

	}
	catch (const std::exception& e)
	{
		std::cout << e.what() << std::endl;
	}


	return 0;
}
相关推荐
落榜程序员27 分钟前
Java 基础-32-枚举-枚举的应用场景
java·开发语言
晓131332 分钟前
第九章Python语言高阶加强-面向对象篇
java·开发语言
2301_7760452332 分钟前
什么是异步?
开发语言·区块链
Wx120不知道取啥名2 小时前
C语言跳表(Skip List)算法:数据世界的“时光穿梭机”
c语言·数据结构·算法·list·跳表算法
xy_optics5 小时前
用matlab探索卷积神经网络(Convolutional Neural Networks)-3
开发语言·matlab·cnn
独好紫罗兰5 小时前
洛谷题单3-P1720 月落乌啼算钱(斐波那契数列)-python-流程图重构
开发语言·算法·leetcode
慕容莞青6 小时前
MATLAB语言的进程管理
开发语言·后端·golang
暗碳7 小时前
vscode c语言环境配置
c语言·ide·vscode
jimin_callon7 小时前
VBA第三十八期 VBA自贡分把表格图表生成PPT
开发语言·python·powerpoint·编程·vba·deepseek
愚戏师8 小时前
软件工程(应试版)图形工具总结(二)
数据结构·c++·python·软件工程