只是想知道,为什么最好把一个类放在枚举上
当然,投掷课程的开销更大?
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或其他东西的类声明一个类。更多代码,更大的二进制......有什么好处?
答案 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)
开销并不重要,因为例外总是很昂贵。类的实例可以包含更多信息,您可以按基础捕获。