为什么要在枚举上放一个课?

Mat*_*att 5 c++ exception-handling

只是想知道,为什么最好把一个类放在枚举上

肯定扔课程的开销更大?

例如

enum MyException
{
   except_a,
   except_b,
   except_c
}


void function f(){
  throw a;
}


int main(int arc, char* argv[]){

  try{

  } catch (MyException e){
    switch(e){
      except_a: break;
      except_b: break;
      except_c: break;
    }
  }

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

除了开销.我还需要为每个可能覆盖std :: exception或其他东西的类声明一个类.更多代码,更大的二进制......有什么好处?

Jam*_*lis 9

以下两个catch块中的哪一个更容易理解:

try {
    do_something();
}
catch (const int&) {
    // WTF did I catch?
}
catch (const std::out_of_range&) {
    // Oh, something was out of range!
}
Run Code Online (Sandbox Code Playgroud)

异常类的名称应该告诉您抛出异常的原因; int没有告诉你任何事情,你只知道你抓到了一个int,无论那意味着什么.


要考虑使用枚举而不是整数的更新示例,以下哪项更清楚:

try{
    do_something();
} 
// (1) Catch an enum:
catch (MyException e) {
    switch(e) {
    except_a: break;
    except_b: break;
    except_c: break;
    default:  throw; // Don't forget, you have to throw any exceptions 
                     // that you caught but don't actually want to catch!
    }
}
// (2) Catch specific exceptions
catch (const ExceptionA&) { }
catch (const ExceptionB&) { }
catch (const ExceptionC&) { }
Run Code Online (Sandbox Code Playgroud)

没有理由更喜欢第一种形式:没有性能优势,代码不太清晰,更容易出错.在您的示例中,如果您没有处理异常,则忘记重新抛出异常,因此如果有人后来except_dMyException枚举中添加了异常,您就会在不知不觉中捕获它.


至于你的"开销"问题,这取决于,但可能不是.抛出异常应该是(相对)罕见的,如果你有一个性能真正重要的紧密循环,那么你也不会使用异常.

使用类层次结构异常的好处是,它们允许你写更清晰的代码,就像使用非本地控制流(例外),而不是像错误代码返回值的其他方法允许你写更清晰的代码的好处(至少当你正确使用异常时).


sbi*_*sbi 5

给定的

enum MyException
{
   except_a,
   except_b,
   except_c
}
Run Code Online (Sandbox Code Playgroud)

编写一个只捕获except_c异常的 catch 子句。

struct my_except {};
struct my_except_a : my_except {};
struct my_except_b : my_except {};
struct my_except_c : my_except {};
Run Code Online (Sandbox Code Playgroud)

这很容易,因为您可以捕获基类或派生类。

派生的许多共同优点适用于异常。例如,基类可以代替派生类,而代码只需要知道基类来处理派生异常。这是多态的一种形式,而enum是一种类型的转换。

关于多态的一般规则也适用于这里:每当您想在类型上使用 switch 时,您就是在忽视多态的优势。一旦代码扩展到数百 kLoC,您就会发现自己遇到的问题,并且您需要添加新类型。使用多态,这很容易,因为大多数代码只处理基类引用就可以了。
使用 type enum,你必须搜索每一个switch语句enum并检查是否需要调整它。

像这样的事情已经杀死了不止一家公司。


这是事后的想法:当他们这样做一段时间后,用户通常会开始将各种数据添加到他们的异常类型中。一个经典的做法是在异常的构造函数中使用__FILE__and__LINE__来查看异常来自哪里。但这也需要异常作为类类型。