[C++] Uso y detalles de excepciones

Métodos tradicionales de error y excepción del lenguaje C

El lenguaje C se usa generalmente assertpara manejar errores. assertDe hecho, es muy bueno. Puede indicar el número de líneas con errores. Sin embargo, asserttiene un defecto fatal, es decir, assertel programa finalizará después de activarse. Otro punto es que no funciona en releaseel medio ambienteassert

Métodos de manejo de excepciones de C++

Las excepciones son una forma de manejar errores. Cuando se activa la condición de juicio anormal, la información de la excepción se capturará automáticamente, pero el programa no finalizará y continuará ejecutándose. Esto no hará que un usuario active una excepción y causará que todos los usuarios estar desconectado..

  • throw: cuando ocurre un problema en el programa, se lanza una excepción mediante throw.
  • catch: las excepciones se pueden detectar mediante catch y throw pasa la información para capturar.
  • try: en el bloque de código de prueba, puede colocar el módulo que desea detectar excepciones. Try generalmente va seguido de muchas capturas para detectar excepciones.
try
{
    
    
  // 保护的标识代码
}catch( ExceptionName e1 )
{
    
    
  // catch 块
}catch( ExceptionName e2 )
{
    
    
  // catch 块
}catch( ExceptionName eN )
{
    
    
  // catch 块
}

ExceptionName: nombre de clase de excepción

uso inusual

Principios de emparejamiento y lanzamiento de excepciones

  • Las excepciones se generan al lanzar objetos y la coincidencia se basa en el tipo de objeto .
  • El código que desencadena la excepción buscará la captura más cercana a partir del lanzamiento y luego será capturada.
  • Después de que se lanza una excepción, en realidad es una variable que está a punto de ser destruida y es necesario generar un objeto de copia, porque el objeto de excepción lanzado es un objeto temporal y se destruirá cuando salga del alcance, y es también este objeto de copia que se captura.
  • catch(...) puede detectar cualquier tipo de excepción, pero no aparece ningún mensaje de error.
  • El tipo de excepción lanzada puede ser un objeto de una clase derivada y luego capturado por la clase base.

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

Relanzamiento de excepción

Es posible que un solo catch no pueda manejar completamente una excepción. Después de un procesamiento de corrección, se espera que se entregue a una función de la cadena de llamadas externa para su procesamiento. El catch puede pasar la excepción a una función de nivel superior para su procesamiento. volviéndolo a lanzar.

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

Para el programa anterior, si se activa una excepción, arrel espacio no se liberará correctamente, lo que provocará una pérdida de memoria. Puede modificarlo de la siguiente manera para capturar la excepción dos veces en **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;
}

De esta forma no habrá problema de puntero nulo.

Problemas de seguridad inusuales

  • Es mejor no generar excepciones en el constructor, lo que puede provocar una inicialización incompleta.
  • Es mejor no generar excepciones en el destructor, lo que puede provocar una limpieza de recursos incompleta.

Sistema de excepción personalizado

En el uso real, muchas empresas personalizarán su propio sistema de excepciones para la gestión de excepciones estandarizada, porque si todos lanzan excepciones a voluntad en un proyecto, entonces la persona que llama externamente básicamente no tendrá forma de jugar, por lo que en la práctica, se creará un conjunto de excepciones heredadas. ser definido sistema normativo. De esta manera, lo que todos arrojan son objetos de clase derivados heredados, simplemente captura una clase base.

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

Si se trata de un error de red, podemos escribirlo para volver a intentar enviar tres veces antes de generar una excepción.

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; // 重新抛出
			}
		}
	}
}

Sistema de excepción de la biblioteca estándar de C++

Supongo que te gusta

Origin blog.csdn.net/AkieMo/article/details/132220587
Recomendado
Clasificación