【发布时间】:2011-05-08 06:26:17
【问题描述】:
出于 X 或 Y 的原因,人们在必要时在 C++ 中使用哪些错误处理方案来避免异常?我已经实施了自己的策略,但我想知道其他人的想法,并就每种方法的优缺点进行讨论
现在,为了解释我在特定项目中使用的方案,可以这样总结。通常需要抛出的方法,实现如下接口:
bool methodName( ...parameters.... , ErrorStack& errStack)
{
if (someError) { errStack.frames.push_back( ErrorFrame( ErrorType , ErrorSource ) );
return false;
}
... normal processing ...
return true;
}
简而言之,返回参数表示处理是否正常或发生错误。错误堆栈基本上是包含错误详细信息的错误帧的 std::vector:
enum ErrorCondition {
OK,
StackOverflowInminent,
IndexOutOfBounds,
OutOfMemory
};
struct ErrorFrame {
ErrorCondition condition;
std::string source;
ErrorFrame( ErrorCondition cnd , const char* src ) : condition(cnd) , source(src) {}
inline bool isOK() const {
return OK == condition;
}
};
struct ErrorStack {
std::vector< ErrorFrame > frames;
void clear() {
frames.clear();
}
};
这种方法的优点是详细的错误堆栈,类似于 java 异常给出的错误,但没有异常的运行时开销。主要缺点是(除了非标准性之外,我仍然必须以某种方式处理来自第三方代码的异常并转换为 ErrorCondition),这是难以维护 ErrorCondition 枚举,因为源库的多个组件需要不同的错误,因此该策略的第二个版本可以为 errorConditions 使用某种继承层次结构,但我仍然对实现它的最佳方法没有信心
【问题讨论】:
-
“这种方法的优点是详细的错误堆栈,类似于 java 异常给出的错误,但没有异常的运行时开销。”您确实意识到使用异常的“运行时开销”与维护此堆栈的成本相比是微不足道的,对吧?
-
也许我错过了你的观点,但我的理解是,即使没有抛出异常,异常处理也会产生运行时成本。在这种情况下,没有错误时唯一的额外成本是在每个相关函数上传递额外的引用
-
在您的实现中存在大量开销,因为必须检查每个函数是否通过或失败。
-
由于您使用的是标准库
string和vector,因此您已经在使用异常,因为标准库分配器必须使用异常来传达分配错误。 -
绝大多数异常处理开销仅在抛出异常时才会产生。在正常操作期间,开销小于您在此处执行的操作。 “我们应该忘记小的效率,比如大约 97% 的时间:过早的优化是万恶之源”——Knuth
标签: c++ exception-handling error-handling stack-trace