我正在编写一个自定义C ++异常类(因此我可以通过C API将C ++中出现的异常传递给另一种语言)。
我最初的攻击计划是按照以下步骤进行:
//C++
myClass
{
public:
myClass();
~myClass();
void foo() // throws myException
int foo(const int i, const bool b) // throws myException
} * myClassPtr;
// C API
#ifdef __cplusplus
extern "C" {
#endif
myClassPtr MyClass_New();
void MyClass_Destroy(myClassPtr p);
void MyClass_Foo(myClassPtr p);
int MyClass_FooBar(myClassPtr p, int i, bool b);
#ifdef __cplusplus
};
#endif
我需要一种能够将C ++代码中抛出的异常传递给C端的方法。我想传递给C方的信息如下:
(a)中。什么 (b)中。哪里 (C)。简单堆栈跟踪(只是它们发生的错误消息序列,没有调试信息等)
我想修改我的C API,以便API函数获取指向结构ExceptionInfo的指针,该结构将在使用调用结果之前包含任何异常信息(如果发生异常)。
因此,在C API中公开的C ++方法将实现如下:
//我必须承认,对于这种实施(维护噩梦除外)有一些奇怪的“ha”“ - 这一定是更好的方法吗?
// ExceptionInfo default ctor initialized to no error
void MyClass::foobarTrappedExceptionWrapper(ExceptionInfo& ei)
{
try {
// call foobar ...
foobar();
}
catch(fast_exception& fe)
{
switch (fe.errcode())
{
//package exception info into ei for C consumption
}
}
catch(std::exception &e)
{
//package exception info into ei for C consumption
}
}
C API中公开的每个C ++方法的实现都需要包含在try / catch语句中(参见上面的代码片段)。对此的性能影响似乎非常严重(根据此article):
“这是一个错误(具有高运行时间 成本)使用C ++异常处理 对于频繁发生的事件,或 对于在附近处理的事件 检测点。“
与此同时,我记得在C ++时代的某个地方读过,虽然异常处理都很昂贵,但实际发生异常时只会造成代价高昂。那么,哪个是正确的?该怎么办?。是否有另一种方法可以安全地捕获错误并将结果错误信息传递给C API?或者这是一个次要考虑因素(毕竟这篇文章很老了,从那以后硬件有所改进)。
[编辑]
删除了问题2,因为我找到了一种创建简单堆栈跟踪here的方法。
答案 0 :(得分:2)
的答案
评论在C中传递C ++异常
继承或不继承std :: exception的选择对性能没有影响;文章提到传播异常和执行堆栈展开的事实是昂贵的(无论异常的类型)。在C世界中传递异常方面......错误处理C通常使用整数返回类型和错误代码完成,但是如果你想传递一个C ++对象,那么如果你可以多态复制异常类型,然后你可以简单地在堆上构造一个副本,然后传递异常对象作为类型 void * ,如果你需要从该对象中提取信息,那么你可以创建C在C ++中实现的接口,它将 void * 对象强制转换为指向异常类型的指针并提取相应的字段。另一种选择,如果您想要的是what()消息,则传递消息的strdup()。但请记住,如果std :: bad_alloc是您处理的异常之一,那么需要分配/复制的任何东西都不会起作用(换句话说,如果由于内存不足而导致失败,则分配更多内存不是个好主意。)
俗话说“在罗马时,像罗马人那样做”......我自己的建议是在C语言中使用返回状态代码和错误代码,并在C ++中使用异常处理。我真的不愿意尝试将C ++异常对象引入C世界。还要记住,C ++代码调用C代码比调用C ++代码的C代码更常见。如果要为C ++代码创建C交互,那么它们应该像C接口一样,即返回错误状态代码。如果您的C ++代码调用返回错误状态代码的C函数,则抛出异常而不是返回基础C代码失败的错误状态代码是合理的。但是,在这种情况下,您处于C ++空间并且不必担心异常交叉回C代码。但是,如果您回到C世界,我建议您记录您拥有的任何信息并使用错误状态代码。
另外,假设std :: exception :: what()返回一个描述发生了什么的char *对象,而你的API返回一个表示异常类型的整数代码......好吧,这对其他人来说真的很混乱使用你的代码。当我看到你在switch语句中使用waht()时,我就要评论你不能打开一个字符串,然后不得不进行双重操作并意识到它意味着与平常不同的东西。