[C++] Exception usage and details

Traditional C language error and exception methods

The C language is generally used assertto handle errors. assertIt is indeed very good. It can prompt the number of lines with errors. However, assertit has a fatal shortcoming, that is, assertthe program will be terminated after being triggered. Another point is that it does not work in releasethe environment. assertof.

C++ exception handling methods

Exceptions are a way to handle errors. When the abnormal judgment condition is triggered, the exception information will be automatically captured, but the program will not terminate and will continue to run. This will not cause one user to trigger an exception and cause all users to be offline. .

  • throw: When a problem occurs in the program, an exception is thrown through throw.
  • catch: Exceptions can be caught through catch, and throw passes the information to catch.
  • try: In the try code block, you can put the module you want to catch exceptions. Try is usually followed by many catches to catch exceptions.
try
{
    
    
  // 保护的标识代码
}catch( ExceptionName e1 )
{
    
    
  // catch 块
}catch( ExceptionName e2 )
{
    
    
  // catch 块
}catch( ExceptionName eN )
{
    
    
  // catch 块
}

ExceptionName: Exception class name

unusual use

Exception throwing and matching principles

  • Exceptions are raised by throwing objects , and matching is based on the object type .
  • The code that triggers the exception will look for the nearest catch starting from throw and then be caught.
  • After an exception is thrown, it is actually a variable that is about to be destroyed, and a copy object needs to be generated, because the exception object thrown is a temporary object and will be destroyed when it goes out of scope, and it is also this copy object that is captured.
  • catch(...) can catch any type of exception, but there is no error message.
  • The thrown exception type can be an object of a derived class and then captured by the base class.

#include<iostream>
using namespace std;

double Division(int a, int b)
{
    
    
	if (b == 0)
	{
    
    
		throw "除0错误!";
	}
	else
	{
    
    
		return double(a / b);
	}
}

void Func()
{
    
    
	int a,b;
	cin >> a >> b;
	cout << Division(a, b) << endl;
}

int main(void)
{
    
    
	try
	{
    
    
		Func();
	}
	catch (const char* errmsg)
	{
    
    
		cout << errmsg << endl;
	}
	catch (...)
	{
    
    
		cout << "未知错误" << endl;
	}

	return 0;
}

Exception rethrow

It is possible that a single catch cannot completely handle an exception. After some correction processing, it is hoped that it will be handed over to an outer call chain function for processing. The catch can pass the exception to a higher-level function for processing by re-throwing it.

#include<iostream>
using namespace std;

double Division(int a, int b)
{
    
    
	if (b == 0)
	{
    
    
		throw "除0错误!";
	}
	else
	{
    
    
		return double(a / b);
	}
}

void Func()
{
    
    
	int* arr = new int[10];

	int a, b;
	cin >> a >> b;
	cout << Division(a, b) << endl;
	
	cout << "delete[]" << arr << endl;
	delete[]arr;
}

int main(void)
{
    
    
	try
	{
    
    
		Func();
	}
	catch (const char* errmsg)
	{
    
    
		cout << errmsg << endl;
	}
	catch (...)
	{
    
    
		cout << "未知错误" << endl;
	}

	return 0;
}

For the above program, if an exception is triggered, arrthe space will not be released correctly, thus causing a memory leak. You can modify it as follows to capture the exception twice in **Func()**.

#include<iostream>
using namespace std;

double Division(int a, int b)
{
    
    
	if (b == 0)
	{
    
    
		throw "除0错误!";
	}
	else
	{
    
    
		return double(a / b);
	}
}

void Func()
{
    
    
	int* arr = new int[10];
	try
	{
    
    
		int a, b;
		cin >> a >> b;
		cout << Division(a, b) << endl;
	}
	catch(...){
    
    
		cout << "delete[]" << arr << endl;
		delete[]arr;
		throw;
	}
	
	cout << "delete[]" << arr << endl;
	delete[]arr;
}

int main(void)
{
    
    
	try
	{
    
    
		Func();
	}
	catch (const char* errmsg)
	{
    
    
		cout << errmsg << endl;
	}
	catch (...)
	{
    
    
		cout << "未知错误" << endl;
	}

	return 0;
}

This way there will be no null pointer problem.

Unusual security issues

  • It is best not to throw exceptions in the constructor, which may lead to incomplete initialization.
  • It is best not to throw exceptions in the destructor, which may result in incomplete resource cleanup.

Custom exception system

In actual use, many companies will customize their own exception system for standardized exception management, because if everyone throws exceptions at will in a project, then the outer caller will basically have no way to play, so in practice, a set of inherited exceptions will be defined. normative system. In this way, what everyone throws are inherited derived class objects. Just capture a base class.

#include<iostream>
#include<Windows.h>
#include<string>
using namespace std;

double Division(int a, int b)
{
    
    
	if (b == 0)
	{
    
    
		throw "除0错误!";
	}
	else
	{
    
    
		return double(a / b);
	}
}

void Func()
{
    
    
	int* arr = new int[10];
	try
	{
    
    
		int a, b;
		cin >> a >> b;
		cout << Division(a, b) << endl;
	}
	catch(...){
    
    
		cout << "delete[]" << arr << endl;
		delete[]arr;
		throw;
	}
	
	cout << "delete[]" << arr << endl;
	delete[]arr;
}

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 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;
};

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;
	}
};


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();
}

int main()
{
    
    
	while (1)
	{
    
    
		try 
		{
    
    
			Sleep(500);
			HttpServer();
		}
		catch (const Exception& e) // 这里捕获父类对象就可以
		{
    
    
			// 多态
			cout << e.what() << endl;
		}
		catch (...)
		{
    
    
			cout << "Unkown Exception" << endl;
		}
	}
	return 0;
}

If it is a network error, we can write it to retry sending three times before throwing an exception.

void SeedMsg(const string& s)
{
    
    
	// 要求出现网络错误重试三次
	srand(time(0));
	if (rand() % 3 == 0)
	{
    
    
		throw HttpServerException("网络错误", 500, "get");
	}
	else if (rand() % 4 == 0)
	{
    
    
		throw HttpServerException("权限不足", 101, "post");
	}

	cout << "发送成功:" << s << endl;
}

void HttpServer()
{
    
    
	// 要求出现网络错误,重试3次
	string str = "今晚一起看电影怎么样?";
	//cin >> str;
	int n = 3;
	while (n--)
	{
    
    
		try
		{
    
    
			SeedMsg(str);

			// 没有发生异常
			break;
		}
		catch (const Exception& e)
		{
    
    
			// 网络错误 且  重试3次内
			if (e.getid() == 500 && n > 0)
			{
    
    
				continue;
			}
			else
			{
    
    
				throw e; // 重新抛出
			}
		}
	}
}

Exception system of C++ standard library

Guess you like

Origin blog.csdn.net/AkieMo/article/details/132220587