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

时间:2011-02-19 03:37:33

标签: c++ exception-handling

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

当然,投掷课程的开销更大?

e.g。

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

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

6 个答案:

答案 0 :(得分:9)

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

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

异常类的名称应告诉您抛出异常的原因; 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&) { }

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


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

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

答案 1 :(得分:4)

给出

enum MyException
{
   except_a,
   except_b,
   except_c
}

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

使用

struct my_except {};
struct my_except_a : my_except {};
struct my_except_b : my_except {};
struct my_except_c : my_except {};

这很简单,因为你可以捕获基类或派生类。

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

关于多态的一般规则也适用于此: 每当你想要在类型上使用切换时,你就会忽略多态的优点。 你遇到的问题一旦代码扩展到数百kLoC,就会看到自己进入,你需要添加一个新类型。使用多态,这很容易,因为大多数代码只能处理基类引用 对于enum类型,您必须 搜索switch 上的每个enum语句,并检查是否需要调整它。

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


这是一个事后的想法:当他们做了一段时间后,用户通常会开始将各种数据添加到他们的异常类型中。经典之作是在异常的构造函数中使用__FILE____LINE__,以便能够查看异常的来源。但是,这也需要例外类型。

答案 2 :(得分:3)

类中可以包含类似错误消息的内容,并且可以使用一个有意义的名称来说明它所代表的异常类型。如果你看到int被抛出,你怎么知道它导致了什么样的错误?

答案 3 :(得分:1)

调度异常的开销可能远远超过复制一个简单的类。我在this question中测量了数千个周期。所以,表现基本没有实际意义。

此外,作为类的唯一成员的enum值与enum值一样快,并且没有类。例外可以像随机笔记的刮刮片,以摆脱堵塞。你很可能想要更多的数据,这些数据最初(喘息)会使开销翻倍,而值得两倍int s。

最简单和最好的做法是从std:exception开始,只有EVER抛出从中派生的类。

答案 4 :(得分:0)

这不是关于表现。抛出异常并不是您希望在CPU密集型算法中经常发生的事情。解除堆栈的开销远远超过抛出对象的进位。

关于能够捆绑有关发生何种错误的信息。这是为了让你的图书馆的用户明白你所犯的错误和原因。整数或浮点数实际上并不包含太多信息。

答案 5 :(得分:0)

开销并不重要,因为例外总是很昂贵。类的实例可以包含更多信息,您可以按基础捕获。