我正在为用C ++编写的一些功能开发一个C api,我想确保没有任何异常从任何导出的C函数中传播出来。
这样做的简单方法是确保每个导出的函数都包含在:
中try {
// Do the actual code
} catch (...) {
return ERROR_UNHANDLED_EXCEPTION;
}
假设我知道在C ++代码中经常遗漏的一个异常是std :: bad_alloc,我想特别对待它我会写这样的东西:
try {
// Run the actual code
} catch (std::bad_alloc& e) {
return ERROR_BAD_ALLOC;
} catch (...) {
return ERROR_UNHANDLED_EXCEPTION;
}
是否有可能以一种巧妙的方式对其进行分解,以便我可以全局处理一些错误而不为每个导出函数添加一个新的catch语句用于异常处理程序?
我知道使用预处理器可以解决这个问题,但在走这条路之前,我确保没有其他方法可以做到。
答案 0 :(得分:28)
您只能对所有可能的异常使用一个处理函数,并从每个或您的API实现函数中调用它,如下所示:
int HandleException()
{
try
{
throw;
}
// TODO: add more types of exceptions
catch( std::bad_alloc & )
{
return ERROR_BAD_ALLOC;
}
catch( ... )
{
return ERROR_UNHANDLED_EXCEPTION;
}
}
在每个导出的函数中:
try
{
...
}
catch( ... )
{
return HandleException();
}
答案 1 :(得分:4)
已经有了一个很好的答案。但仅仅是FYI,它被称为“例外调度员”成语,请参阅C++ FAQ。
答案 2 :(得分:1)
怎么样:
try{
//Your code here
} catch(std::exception e)
{
return translateExceptionToErrorCode(e);
} catch(...)
{
return UNKNOWN_EXCEPTION_THROWN;
}
答案 3 :(得分:1)
Jem回答比这个解决方案简单得多。但是可以使用模板替换预处理器宏的使用。这样的事情(你可以做的更多改进):
template <class T, void (T::*FUNC)()>
class CatchWrapper
{
public:
static void WrapCall(T* instance)
{
try
{
(instance->*FUNC)();
}
catch (std::bad_alloc&)
{
// Do Something 1
}
catch (std::exception& e)
{
// Do Something 2
}
catch (...)
{
// Do Something 3
}
}
};
class Foo
{
public:
void SomeCall()
{
std::cout << "Do Something" << std::endl;
}
};
int main(int argc, char* argv[])
{
Foo i;
CatchWrapper<Foo, &Foo::SomeCall>::WrapCall(&i);
return 0;
}
答案 4 :(得分:0)
不要使用catch(...)
,除非您计划或多或少立即重新投掷。您肯定会丢失任何错误信息,以帮助您找出错误原因。
我更喜欢你的第二个方案 - 捕获一组已知的异常,理想情况是因为它们是你的代码将抛出的唯一异常,让剩下的通过 - 允许应用程序崩溃可能是最好的事情,因为你引用了未知的行为,最好是“负责任地崩溃”。
答案 5 :(得分:0)
在语言边界丢失错误信息将是一种遗憾。您真的应该尝试将所有异常转换为可从C中使用的错误代码。
你是如何做到的,这取决于你的异常类是什么样的。如果控制异常类层次结构,则可以确保每个类都使用虚方法提供转换。如果没有,您仍然可以发现使用翻译函数并测试它收到的'std :: exception'派生的异常的类型以将其转换为错误代码是很实际的,就像Jem建议的那样(记住:抛出异常会伤害无论如何都要表现,所以不要担心翻译速度慢。)