C++中的异常处理机制:abort、exit、exception类和try..catch语句块

程序运行时有时会遇到错误,导致程序无法正常运行下去,通常程序员会试图预防这种意外。C++异常处理为这种情况提供了一种功能强大而灵活的工具。这里会介绍四种,分别是:
• 调用abort()函数及assert()函数
• 调用exit()函数
• 异常捕获机制try…catch…
• exception类

一. 调用abort()函数及assert()函数

1、abort()函数
abort()函数的原型位于头文件cstdlib(或stdlib.h)中,其典型实现是向标准错误流(即cerr使用的错误流)发送abnormal program termination(程序异常终止),然后终止程序。
调用abort()时,不进行任何清理工作,直接终止程序
示例程序:

#include"iostream"
#include"cstdlib"
 
using namespace std;
 
double hmean(double a, double b);
int main()
{
	double x, y, z;
	cout << "Enter two numbers:";
	while (cin >> x >> y)
	{
		z = hmean(x, y);
		cout << "Harmonic mean of" << x << "and" << y << "is" << z << endl;
		cout << "Enter next set of numbers:";
 
	}
	cout << "end" << endl;
	system("pause");
	return 0;
}
 
double hmean(double a, double b){
	if (a == -b){
		cout << "unenable arguments to hmean()" << endl;
		abort();
	}
	return 2.0*a*b / (a + b);
}

2、assert()函数
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行。
原型定义:

#include <assert.h>
void assert( int expression );

具体工作机制:
assert的作用是先计算表达式expression,如果其值为假(即为0),那么它先向std::error打印一条错误信息,然后通过调用**abort()**来终止程序运行。
例子如下:

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
int main( void )
{
       FILE *fp;
    
       fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,如果不存在就创建一个同名文件
       assert( fp );                           //所以这里不会出错
       fclose( fp );
    
       fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,如果不存在就打开文件失败
       assert( fp );                           //所以这里出错
       fclose( fp );                           //程序永远都执行不到这里来
       return 0;
}

常见使用场景:
一个非常简答的使用规则是:在方法或者函数的最开始使用。如果在方法的中间使用,则需要慎重考虑是否是应该的。在一个功能过程执行中出现的问题几乎都是异常。

1)在函数开始处检查传入参数的合法性,如:

int resetBufferSize(int nNewSize)
{
  //功能:改变缓冲区大小,
  //参数:nNewSize 缓冲区新长度
  //返回值:缓冲区当前长度 
  //说明:保持原信息内容不变     nNewSize<=0表示清除缓冲区
  assert(nNewSize >= 0);
  assert(nNewSize <= MAX_BUFFER_SIZE);
  ...
}

2)每个assert只检验一个条件,因为同时检查多个条件时,如果断言失败,无法直观的判断是哪个条件失败。
问题代码:

assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);

正确代码:

assert(nOffset >= 0);
assert(nOffset+nSize <= m_nInfomationSize);

3)不能使用改变环境的语句,因为assert通常只在DEBUG中生效,如果这么做,会使程序在真正运行时遇到问题。
问题代码如下。错误原因是,如果i+1=100时出错,那么i=100这条命令就没有执行了。

assert(i++ < 100);

正确代码:

 assert(i < 100);
 i++;

4)assert和后面的语句应空一行,以形成逻辑和视觉上的一致感。
5)assert是用来避免显而易见的错误的,而不是处理异常的。
错误和异常是不一样的,错误是不应该出现的,异常是不可避免的。c语言异常可以通过条件判断来处理,其它语言有各自的异常处理机制。

被现代程序抛弃的原因:
频繁的调用assert函数会极大的影响程序的性能,增加额外的开销。
在调试结束后,可以通过在包含#include <assert.h>的语句之前插入**#define NDUBUG**来禁用assert调用。
例子如下:

#include <stdio.h>
#define NDEBUG
#include <assert.h>

二. exit()函数

1、背景知识介绍:
C语言的设计之初就是为Unix系统设计的。而Unix系统是“很多程序相互配合”搭配形成的一个系统。
每个运行着的程序都是进程,而进程就会有父进程,父进程通常是直接启动你的进程。如果一个进程的父进程死亡,它会被init收养,其父进程变为init,而init的父进程是进程0。进程0则是系统启动时启动的第一个进程。
exit()里面的参数,是传递给其父进程的。对父进程来说,你的进程仿佛是一个函数,而函数可以有返回值。
现在可以回答这个问题了:Unix系统中,C/C++的exit()函数的参数到底有什么意义呢?
答案是:exit()的参数,是给自己的父进程使用的。通常一个程序的父进程可能是任何进程,因此我们无法预期我们的父进程是否规定必须要有这个返回值。那么,我们应当提供这个返回值,以保证不同的父进程的需求得到满足。一个典型例子是:make。Makefile对于一个target下面有多条顺序执行的语句,而make作为父进程,会检查每个语句的返回值是否为0,遇到任何一个非0值,都会停止当前rule的执行。而我们知道,make实际上可以执行任何命令、任何程序。因而,任何被make调用的程序必须有正确的返回值。

2、灵魂拷问:为什么会有exit()函数?
答案是:历史原因。虽然现在大多数平台下,直接在main()函数里面return可以直接退出程序。但是在某些平台下,在main()函数里面return会导致程序永远不退出(因为代码已经执行完毕,程序却还没有收到要退出的指令)。换句话说,为了兼容性考虑,在特定的平台下,程序最后一行必须使用exit()才能正常退出,这是exit()存在的重要价值。

3、exit函数的使用
exit():在整个程序中,只要调用exit,程序会先清除包括PCB在内的各种数据结构,然后结束当前进程(或当前程序),把控制权重新交给系统。
exit(0):表示进程正常退出,return 0;
exit(非零):表示进程非正常退出。

三. 异常机制
C++异常是对程序运行过程中发生的异常情况的一种响应,这在C++应用程序开发中应用十分广泛。异常提供了将控制权从程序的一个部分传递到另一个部分的途径。
对异常的处理有3个组成部分:
• 引发异常
• 处理程序顺利捕获异常
• 使用try块
1、C++异常处理的格式

try
{
   //标识可能出现的异常代码段
   throw  抛出一个异常
} 
catch 
{
  //异常处理程序的类型
}
  • try块里面存放可能抛出异常的代码,它后面可以跟一个或多个catch块;

  • throw语句实际是跳转,及命令程序跳转到另一条语句。throw关键字表示引发异常,紧跟后面的值(例如字符串或对象),指出异常特征。

  • throw语句类似执行返回语句,因为他将终止函数的执行;但throw不是将控制权返回给调用程序,而是导致程序沿函数调用顺序后退,直到找到最近的包含try块的函数

  • 如果函数引发异常,而没有try块或没有匹配的处理函数,程序最终将调用**abort()**函数。

  • catch实现捕获任何异常,代码范式如下:

try{
	//会抛出异常的代码
}
catch(...)   //捕获任何异常
{
	//异常处理
}

例子很好!!!!

#include"iostream"
#include"cstdlib"
 
using namespace std;
 
double hmean(double a, double b);
int main()
{
	double x, y, z;
	cout << "Enter two numbers:";
	while (cin >> x >> y)
	{ 
		try{ z = hmean(x, y); }
		catch (const char *s)
		{
			cout << s<< endl;
			//cout << "Harmonic mean of" << x << "and" << y << "is" << z << endl;
			cout << "Enter next set of numbers:";
			continue;
		}
		cout << "Harmonic mean of" << x << "and" << y << "is" << z << endl;
		cout << "Enter next set of numbers:";
 
	}
	cout << "end" << endl;
	system("pause");
	return 0;
 }
 
double hmean(double a, double b){
	if (a == -b){
		throw "unenable arguments to hmean()" ;
		
	}
	return 2.0*a*b / (a + b);
}

四、exception类
较新的C++编译器将异常合并到语言中,例如,为支持该语言,exception头文件(以前为exception.h 或 except.h)定义了exception类,C++可以把它作为其他异类的基类。
代码可以引发exception异常,也可以将exception类作为基类。它有一个返回值为字符串的虚成员函数what()。它返回的字符串的特征随实现而异。需要注意的是,由于这是一个虚方法,因此可以在从exception派生而来的类中重新定义它。
C++库定义了很多基于exception类的异常类型。
例子很好!!!!

#include"iostream"
 
using namespace std;
 
class nn_error : public std::exception {
public:
	explicit nn_error(const std::string& msg) : msg_(msg) {}
	const char* what() const throw() override { return msg_.c_str(); }
private:
	std::string msg_;
};
double hmean(double a, double b);
int main()
{
	double x, y, z;
	cout << "Enter two numbers:";
	while (cin >> x >> y)
	{
		try{ z = hmean(x, y); }
		catch (const nn_error& e)
		{
			cout << e.what() << endl;
			//cout << "Harmonic mean of" << x << "and" << y << "is" << z << endl;
			cout << "Enter next set of numbers:";
			continue;
		}
		cout << "Harmonic mean of" << x << "and" << y << "is" << z << endl;
		cout << "Enter next set of numbers:";
 
	}
	cout << "end" << endl;
	system("pause");
	return 0;
}
 
double hmean(double a, double b){
	if (a == -b){
		throw nn_error("unenable arguments to hmean()");
 
	}
	return 2.0*a*b / (a + b);
}

参考链接:
C++异常处理之abort()、异常机制、exception类:https://blog.csdn.net/u012507022/article/details/51285934
Linux进程退出–exit与return的区别:https://blog.51cto.com/ab3813/1761915
C/C++ assert()函数用法总结:https://www.cnblogs.com/lvchaoshun/p/7816288.html

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这个错误提示是因为HBase RegionServer加载了一个或多个协处理器(Coprocessor),其至少一个协处理器抛出了异常,导致RegionServer崩溃。在这个错误提示,协处理器的名称是MultiRowMutationEndpoint。 协处理器是一种机制,可以让HBase用户在RegionServer上运行自定义代码来处理HBase的数据。协处理器可以用来实现各种功能,比如数据过滤、数据转换、数据合并等。但是,协处理器也可能出现问题,导致RegionServer运行异常。常见的协处理器问题包括: 1. 协处理器代码有缺陷,导致异常抛出。 2. 协处理器与HBase版本不兼容。 3. 协处理器配置不正确,导致异常抛出。 针对这个错误,你可以尝试以下解决方法: 1. 检查协处理器代码:协处理器代码可能有缺陷,导致抛出异常。可以检查协处理器代码,修复问题,并重新加载协处理器。 2. 检查协处理器与HBase版本是否兼容:协处理器可能与HBase版本不兼容,需要检查协处理器与HBase版本的兼容性,并采取相应的措施,如升级协处理器或者降低HBase版本。 3. 检查协处理器配置:协处理器配置可能不正确,导致异常抛出。可以检查协处理器配置,确保配置正确。 4. 禁用协处理器:如果无法解决协处理器问题,可以尝试禁用协处理器,看是否可以解决问题。可以在HBase Shell使用disable命令禁用协处理器。 希望以上解决方法能帮助你解决问题。如果还有其他问题,请随时向我提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值