正确使用异常

本文关键字:异常 | 更新日期: 2023-09-27 18:09:23

我不确定是否完全理解异常应该如何使用。我经常在想"我应该在这里,还是在更高的调用堆栈中捕获这个?"诸如此类的问题。但是我已经创建了一个小的异常类,有一些类似c#的异常,可以显示异常堆栈:

class Exception : public std::exception
{
protected:
   std::string _trace;
public:
   Exception()
    : _trace( "[ERROR - " + (std::string) DateTime() + "]"
   { }
   Exception & push( const std::string & msg )
   {
      this->_trace += ''n't' + msg;
      return *this;
   }
   virtual const char * what() const
   {
      return this->_trace.c_str();
   }
};

我可以这样使用:

function depth0()
{
    try
    {
        depth1();
    }
    catch( Exception & exc )
    {
        throw exc.push( "depth0() - Failed." );
    }
}
function depth1()
{
    try
    {
        depth2();
    }
    catch( Exception & exc )
    {
        throw exc.push( "depth1() - Failed." );
    }
}
function depth2()
{
    try
    {
        depth3();
    }
    catch( Exception & exc )
    {
        throw exc.push( "depth2() - Failed." );
    }
}
function depth3()
{
    if( something goes wrong )
    {
        throw Exception().push( "depth3() - Failed." );
    }
}
try
{
    depth0();
}
catch( Exception & exc )
{
    std::cout << exc.what() << std::endl;
}

我不需要在调用栈的每个深度都进行catch和throw,这只是一个例子。

这是使用异常的正确方法吗?这不是违背了例外的哲学吗?(我还不明白)。

谢谢你:)

PS:我使用Java和c#标签,因为这是所有关于异常的一般情况,即使样本是在c++中。

正确使用异常

作为一般规则:捕获可以处理的异常。并在可能的情况下捕获特定的异常。就像连接到数据库一样——您永远不希望用户看到一个异常——在最坏的情况下,它包含连接字符串的详细信息。因此,您的业务逻辑层必须捕获数据库异常并尽可能地处理它(再次尝试连接,记录异常等),并抛出一些前端可以保存处理的异常(自定义数据库连接异常或其他没有详细信息的异常)。

另一方面,你不能很好地处理的东西(内存不足异常或诸如此类),你可以在应用程序级别捕获并响应一些(如果可能的话,自定义但至少是通用的)信息给用户,告诉他们出了问题。如果可能的话,使应用程序进入稳定状态