我正在考虑在我写的一些库中使用异常处理。 代码库最终可以在许多dll中实现。 我知道在dll中使用异常处理是一个坏主意 - 但是,执行以下操作是否安全?
class IDllSafeException
{
public:
virtual void AddRef() = 0;
virtual void Release() = 0;
virtual int GetErrorCode() const = 0;
virtual const char * What() const = 0;
};
假设这是一种有效的方法,我真的很想按值而不是指针来捕捉。这样我就可以有一个自动调用Release()的包装类。
...因此
template <typename T>
class SafeExceptionT
{
public:
SafeExceptionT(T *);
SafeExceptionT(SafeExceptionT &);
SafeExceptionT & operator=(SafeExceptionT &);
~SafeExceptionT();
int GetErrorCode() const;
const char * What() const;
private:
T * m_pException;
};
typedef SafeExceptionT<IDllSafeException> SafeException;
作为模板意味着所有catch块都会生成自己的布局,并且可以在析构函数中调用m_pException-&gt; Release()(复制时使用AddRef())。我也可以根据需要实现不同类型的异常。
我的捕获块看起来像这样......
try
{
ThrowSomething();
}
catch(SafeException except)
{
const char * psz = except.What();
int nErrorCode = except.GetErrorCode();
}
...
void ThrowSomething()
{
// Concrete implementation omitted for brevity
throw new DllSafeException(1, "something went wrong");
}
我原以为这会起作用,但我的异常处理程序不会被捕获,即使我是SafeException的非显式构造函数。
但是我似乎只能通过指针捕捉......
try
{
ThrowSomething();
}
catch(SafeException except)
{
/// IGNORED!
...
}
catch(IDllSafeException * pExcept)
{
// CAUGHT BY POINTER but we now have to micro-manage.
const char * psz = pExcept->What();
int nErrorCode = pExcept->GetErrorCode();
pExcept->Release();
}
是否有关于如何在异常处理程序中匹配类型的特殊规则?
答案 0 :(得分:0)
如果有人感兴趣,上面的代码通过使用抽象基类并依赖于编译器之间的一致vtable布局,成功地绕过了dll边界异常问题。
我在VS2008和VS2017上进行了测试。我在每个环境中都有一个dll,每个环境都有一个控制台应用程序。 dll引发了异常,异常类在内部聚合了一个对象,以确保发生堆分配。
我还在不同的dll / console应用程序之间混合和匹配了C-runtime(static vs dll)的版本。我可以成功地在dll鸿沟中提出/捕捉我的异常。
正如所料,vtable布局确保delete /〜tor以正确的二进制文件发生。
唯一需要注意的是你必须通过抽象接口抛出。这也意味着确保您手动调用pEx-&gt; Release。我知道这不是很好但我仍然不知道为什么我的其他类不通过它的非显式构造函数捕获异常。