我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++11中异常处理机制详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++11中异常处理机制详解

一、异常的引入

传统的C语言处理异常的方式有两种:

1.终止程序:使用assert断言语句,如果发生内存错误等,比如内存泄漏或者除0错误,都会直接终止程序。

2.返回错误码:通过错误码判断发生的异常的类型是什么,如系统的很多库的接口程序通过把错误码放到errno中,表示错误。

在实际中的C语言程序基本都是通过返回错误码的方式来处理错误的,部分情况下使用终止程序来处理比较严重的错误。

二、C++异常的关键字

目前市面上的大部分的主流语言都是使用异常机制来处理错误的,当一个函数发现自己无法处理一些错误的时候会进行抛异常处理,让函数直接跳转到捕获异常的地方去处理异常。

下面介绍C++处理异常的几个关键字:

throw:当问题出现的时候,程序会抛出一个异常,这是通过throw关键字来完成的。

catch:通过异常处捕获异常,catch块主要用于处理异常,或者执行一些其他的操作。

try:try块中的代码标识将被激活的特定异常,它的后面一般会跟一个catch块。

三、异常的抛出与处理规则

double Disvision(int a, int b)
{
    if (b == 0)
    {
        throw  "Disvision by zero condition";
    }
    else
    {
        return ((double)a / (double)b);
    }
}
void Func()
{
    int len, time;
    cin >> len >> time;
    cout << Disvision(len, time) << endl;
}
int main()
{
    try 
    {
        Func();
    }
    catch(const char* errmsg)
    {
        cout << errmsg << endl;
    }
    catch (...)
    {
        cout << "unkown exception" << endl;
    }
    return 0;
}

当向time传入的值为0的时候,调用throw抛出异常,catch会捕获到该异常进行处理。

1.异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪一个catch的处理代码。

2.被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的一个。

在这段程序中,有一个调用链:main()->Func()->Disvision(),在Disvision中抛出异常就会沿着调用链寻找能捕获异常的catch来执行。假设Func()中有一个与main()中一模一样的catch函数,那么除0的异常就会优先调用Func()中的catch,因为它离着最近。

3.catch的异常其实是抛出对象的拷贝,因为真正抛出的对象在出作用域的时候就已经被销毁了,拷贝的对象在catch成功之后也会自动销毁。

4.catch(…)可以捕获任意类型的异常,但问题是不知道异常错误是什么。

5.实际中抛出和捕获的匹配原则有一个例外,并不都是类型完全匹配,可以抛出的派生类对象,使用基类捕获。(要引入多态)

6.当catch异常之后,会沿着catch后的子句继续执行,类似goto,算是异常的一个缺陷。

四、异常缺陷的处理

double Disvision(int a, int b)
{
    if (b == 0)
    {
        throw  "Disvision by zero condition";
    }
    else
    {
        return ((double)a / (double)b);
    }
}
void Func()
{
    int* array = new int[10];
    int len, time;
    cin >> len >> time;
    cout << Disvision(len, time) << endl;
    delete[] array;//一旦抛出异常,这里就不会被执行
}
int main()
{
    try 
    {
        Func();
    }
    catch(const char* errmsg)
    {
        cout << errmsg << endl;
    }
    catch (...)
    {
        cout << "unkown exception" << endl;
    }
    return 0;
}

对于这段代码而言,一旦Division抛出异常就会立刻执行主函数中的catch,delete释放内存就不会被执行。因此我们需要对这种情况进行处理,即在Func中也捕获一次异常,但是不对异常进行处理,只是释放空间:

void Func()
{
    int* array = new int[10];
    int len, time;
    cin >> len >> time;
    try {
        cout << Disvision(len, time) << endl;
    }
    catch (const char* errmsg)
    {
        cout << "释放空间" << endl;
        delete[] array;
        throw;
    }
}

在释放空间之后,直接调用throw表示将捕获到的异常再抛出去。

五、自定义异常体系

class Exception
{
public:
	Exception(const string& errmsg, int id)
		:_errmsg(errmsg)
		, _id(id)
	{}

	virtual string what() const
	{
		return _errmsg;
	}
protected:
	string _errmsg;
	int _id;
};

class SqlException : public Exception
{
public:
	SqlException(const string& errmsg, int id, const string& sql)
		:Exception(errmsg, id)
		, _sql(sql)
	{}

	virtual string what() const
	{
		string str = "SqlException:";
		str += _errmsg;
		str += "->";
		str += _sql;
		return str;
	}

private:
	const string _sql;
};

class CacheException : public Exception
{
public:
	CacheException(const string& errmsg, int id)
		:Exception(errmsg, id)
	{}

	virtual string what() const
	{
		string str = "CacheException:";
		str += _errmsg;
		return str;
	}
};

class HttpServerException : public Exception
{
public:
	HttpServerException(const string& errmsg, int id, const string& type)
		:Exception(errmsg, id)
		, _type(type)
	{}

	virtual string what() const
	{
		string str = "HttpServerException:";
		str += _type;
		str += ":";
		str += _errmsg;
		return str;
	}

private:
	const string _type;
};

void SQLMgr()
{
	srand(time(0));
	if (rand() % 7 == 0)
	{
		throw SqlException("权限不足", 100, "select * from name = '张三'");
	}

	//throw "xxxxxx";
}

void CacheMgr()
{
	srand(time(0));
	if (rand() % 5 == 0)
	{
		throw CacheException("权限不足", 100);
	}
	else if (rand() % 6 == 0)
	{
		throw CacheException("数据不存在", 101);
	}

	SQLMgr();
}

void HttpServer()
{
	// ...
	srand(time(0));
	if (rand() % 3 == 0)
	{
		throw HttpServerException("请求资源不存在", 100, "get");
	}
	else if (rand() % 4 == 0)
	{
		throw HttpServerException("权限不足", 101, "post");
	}
	CacheMgr();
}

void ServerStart()
{
	while (1)
	{
		this_thread::sleep_for(chrono::seconds(1));//休眠1s
		try {
			HttpServer();
		}
		catch (const Exception& e) // 这里捕获父类对象就可以
		{
			// 多态
			cout << e.what() << endl;
		}
		catch (...)
		{
			cout << "Unkown Exception" << endl;
		}
	}
}
int main()
{
	ServerStart();
	return 0;
}

这里使用随机数进行模拟异常的抛出类型,我们使用父类捕获异常,抛出子类异常,使用多态调用子类中的what()函数。

六、异常规范

1.异常规格说明的目的是为了让函数使用者知道。可以在函数的后面接throw类(类型),列出这个函数可能抛的所有异常类型。

2.函数后面接throw(),表示函数不抛异常。

3.若无异常接口声明,则此函数可以抛掷任何类型的异常。

void func() throw(A, B, C, D);//只会抛A/B/C/D中的某种类型的异常
void* operator new(size_t size) throw(bad alloc);//这里表示这个函数只会抛出bad_alloc的异常
void* operator new(size_t size, void* ptr) throw();//这个函数不会抛异常

在C++11中,引入了noexception

bool Compare(int x, int y) noexcept(noexcept(x > y))  //C++11
{
    return x > y;//表示如果x > y不发生异常,则Compare函数不会发生异常。
}

七、异常安全

构造函数完成对象的初始化,最好不要在构造函数中抛异常,否则可能导致对象不完整,或没有完全初始化。

析构函数主要完成资源的清理,最好不要在析构函数中抛异常,否则可能导致资源泄漏(内存泄漏,句柄未关闭)。

C++异常经常会导致资源泄漏的问题,比如在new和delete中抛出了异常,导致内存泄漏,在lock和unlock之间抛出了异常导致死锁,C++经常使用RAII来解决以上问题,关于RAII我们在智能指针中讲解。

八、异常的优缺点

1.优点

1.相比错误码,更加清晰展示出错信息。

2.很多库中包含异常,boost,gtest,gmock等常用的库,使用它们也需要异常。

3.部分函数使用异常更好处理,比如构造函数没有返回值,不方便使用错误码方式处理,比如T&operator这样的函数,只有一个返回值,如果pos越界了只能使用异常或者终止程序处理,没办法通过返回值表示错误。

2.缺点

1.异常类似goto,会导致程序的执行流乱跳,并且非常混乱。

2.C++没有垃圾回收机制,可能导致内存泄漏。

3.各个公司的异常体系不同,有一定的学习成本。

到此这篇关于C++11中异常处理机制详解的文章就介绍到这了,更多相关C++11异常处理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++11中异常处理机制详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

详解C++中的异常和错误处理机制

在C++编程中,异常处理和错误处理机制是非常重要的,它们可以帮助程序员有效地处理运行时错误和异常情况,本文就来介绍一下C++中的异常处理和错误处理机制吧
2023-05-19

C++中的异常处理机制介绍

本篇内容介绍了“C++中的异常处理机制介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!异常处理增强错误恢复能力是提高代码健壮性的最有力的途
2023-06-17

C++ 函数异常详解:错误处理机制浅析

异常是 c++++ 中的错误处理机制,用于处理意外事件。异常处理机制包括 try-catch 块和异常指定符,后者用于在函数签名后指定可能引发的异常类型。标准 c++ 库提供了多种内置异常类型,如 runtime_error 和 logic
C++ 函数异常详解:错误处理机制浅析
2024-05-03

python异常和文件处理机制详解

本文实例讲述了python异常和文件处理机制。分享给大家供大家参考,具体如下: 1 异常处理 Python的异常用 try except finally 来处理. 并且except后还可以跟 else . 引发异常用 raise 如果抛出的
2022-06-04

C++学习之异常机制详解

C++中的异常处理机制可以帮助我们处理程序在运行时可能会遇到的异常情况,比如内存分配错误、文件打开失败等。本文就和大家详细讲讲C++中异常机制的具体使用吧
2023-05-15

如何实现C++中的异常处理机制?

如何实现C++中的异常处理机制?引言:异常处理是编程中非常重要的一部分,它可以提高程序的可靠性和稳定性。在C++中,异常处理机制可以帮助我们处理程序中的错误和异常情况,使得程序的控制流能够在异常发生时进行变更,从而避免程序的崩溃。本文将介绍
如何实现C++中的异常处理机制?
2023-11-02

C++中异常处理问题详细解析

C++中异常处理问题详细解析异常处理是现代编程语言中一个非常重要的概念,它可以帮助程序员有效地处理和响应运行时错误。在C++中,异常处理机制提供了一种结构化的方式来捕捉并处理异常,从而使程序能够在遇到错误时进行适当的处理,而不是直接崩溃。异
2023-10-22

【JAVA 异常处理机制】

文章目录 前言1.java异常处理机制2.try-catch3.finally块4.自动关闭特性5.throw关键字6.throws关键字7.throws的重写规则8.异常分类9.异常API10.自定义异常总结: 前言 在Ja
2023-08-23

C++嵌入式开发中的异常处理机制

c++++异常处理机制在嵌入式开发中至关重要,可处理超出预期的异常,确保系统稳定性。有两种异常类型:标准异常和用户定义异常,可使用throw抛出异常,使用try-catch捕获异常。实战案例展示异常处理在嵌入式应用程序中的应用,处理eepr
C++嵌入式开发中的异常处理机制
2024-05-11

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录