在C++中进行函数级别的异常处理 - 这是一种不好的编程风格吗?

6

关于函数有一个 try-catch 的处理,我认为有时候会非常有用:

bool function() 
try
{
    //do something
}
catch(exception_type & t)
{
   //do something
}

首先要回答的问题是:这种风格在一般情况下是否被认为是不好的?

我用一个具体的例子来说明:

我们有一个使用C和C++编写的项目。在项目中,我们定义了自己的异常类型(不是继承自std::exception的)。我需要集成XML库并将所有异常转换为我们自己的异常类型。因此,基本上最后一步就是捕获来自XML库的所有异常并进行转换。

函数之前的代码:

bool readEntity(...)
{
   while(...)
   { 
      if(...)
      {
         //lot's of code...
      }
   }
}

之后:

bool readEntity(...)
try
{
   while(...)
   { 
      if(...)
      {
         //lot's of code...
      }
   }
}
catch(XMLBaseException & ex)
{
    //create our exception and throw
}

我的想法是:我清楚地表达了将所有派生自一种类型的异常转换为自定义类型,并且保持我们的屏幕没有水平滚动条(因为水平滚动条很糟糕)。

然而,在代码审查期间,我的这种方法被批评为不够明确。

所以我想听听您的想法。

更新: 仅仅为了明确:重构函数不是一个选项。而且实际上它写得很好。


类似的问题(但不是重复的,但可能有趣):https://dev59.com/LnRC5IYBdhLWcg3wUvUS - Johannes Schaub - litb
4个回答

12

在函数级别使用try块的唯一原因就是为了构造函数,否则它是一个有些晦涩的功能,并没有带来太多好处。按照如下方式实现同样容易:

bool readEntity(...)
{
   try
   {
      while(...)
      { 
         if(...)
         {
            //lot's of code...
         }
      }
   }
   catch(XMLBaseException & ex)
   {
       //create our exception and throw
   }
}

如果您在水平滚动方面遇到问题,那么需要做的是分割您的代码。尝试/捕获会增加复杂度,应该体现在嵌套级别中,而不是隐藏。

在构造函数中,这是一个不同的问题:没有其他方法可以在初始化列表中捕获异常:

SomeClass::SomeClass(parameter p1, parameter p2) : Member1(p1), Member2(p2)
try
{ 
}
catch(Exception &ex)
{
    // handle and rethrow
}

当然,如果您在构造过程中遇到异常,除了记录和重新抛出(在构造函数情况下,它肯定会被重新抛出)之外,您很可能无法采取任何措施进行恢复。因为对象尚未完全构建完成,您不能真正地对其进行任何操作。唯一可信的是参数(尽管如果初始化失败,那通常是由于不良参数导致的)。

请参阅此处讨论此问题。


4

需要明确的是:重新抛出和重新包装异常并不是不好的做法,这是一件好事情,因为它最小化了外部依赖的暴露。

然而,函数级别的try-catch旨在用于构造函数初始化。为了节省您代码中的一些水平空间而使用相对较难理解的语言特性是不值得的。如果您真的需要缩进到那么深,请更好地重构嵌套代码!


1

0
那个函数应该返回一个布尔值,因此您可以返回 true 或 false,但是如果该函数失败并且布尔值用于除了成功标志之外的其他事情(这是不好的做法,除非是纯C),它应该抛出异常以向调用者表示它没有工作。

函数的类型仅作为示例。我认为它返回刚创建的实体。但我理解你的观点。 - inazaruk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接