iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++11中异常处理机制详解
  • 743
分享到

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

2024-04-02 19:04:59 743人浏览 泡泡鱼
摘要

目录一、异常的引入二、c++异常的关键字三、异常的抛出与处理规则四、异常缺陷的处理五、自定义异常体系六、异常规范七、异常安全八、异常的优缺点1.优点2.缺点一、异常的引入 传统的C语

一、异常的引入

传统的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异常处理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++11中异常处理机制详解

本文链接: https://www.lsjlt.com/news/168582.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

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

下载Word文档
猜你喜欢
  • c语言怎么计算字符串长度
    在C语言中,可以使用内置的strlen()函数来计算字符串的长度。该函数位于string.h头文件中。以下是一个示例代码: #inc...
    99+
    2024-05-14
    c语言
  • c语言怎么判断三个数的大小
    可以通过比较三个数之间的大小关系来判断它们的大小。以下是一个示例代码: #include <stdio.h> int ...
    99+
    2024-05-14
    c语言
  • c++排序函数sort怎么使用
    在C++中,使用sort函数对容器中的元素进行排序,可以按照默认的升序排列,也可以自定义排序规则。 下面是一个简单的例子,对一个ve...
    99+
    2024-05-14
    c++
  • c++中string的compare函数怎么使用
    在C++中,可以使用string的compare函数来比较两个string对象的大小。该函数的原型如下: int compare(c...
    99+
    2024-05-14
    c++
  • c++中string的compare函数有什么用
    c++中string的compare函数用于比较两个字符串的大小关系。该函数返回一个整数值,表示两个字符串的比较结果。 具体来说,如...
    99+
    2024-05-14
    c++
  • c++中print函数的功能有哪些
    在C++中,通常使用std::cout来进行输出操作,而不是使用print函数。std::cout是C++标准库中的一个输出流对象,...
    99+
    2024-05-14
    c++
  • c语言数据结构怎么使用
    在C语言中,数据结构可以通过定义结构体来实现。以下是一些常见的数据结构的使用方法示例: 链表: #include <std...
    99+
    2024-05-14
    c语言
  • c++中print函数的用法是什么
    在C++中没有内置的print函数,但可以使用cout来输出内容到控制台。cout是C++标准库中的一个输出流对象,可以使用<...
    99+
    2024-05-14
    c++
  • c++中concept的用法是什么
    在C++20中,Concept是一种新的语言特性,用于定义类型要求和约束。Concept可以被用来约束函数模板、类模板和普通函数的参...
    99+
    2024-05-14
    c++
  • c++中concept的作用是什么
    在C++中,concept的作用是定义一种通用的约束,用于限制模板参数的类型范围。通过使用concept,可以在编译时对模板参数进行...
    99+
    2024-05-14
    c++
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作