我正在构建一个共享库,我希望它在不同编译器(如 Windows 上的 MSVC 和 GCC)之间兼容 ABI。我的灵感来自 this blog post .我唯一错过的是跨 DLL 边界抛出异常的能力……所以我做了这个小技巧:
我的图书馆.hpp
class Thrower{
static void(*m_thowFunc)(const char*);
public:
static void setThrowFunction(void(*func)(const char*)){
m_thowFunc = func;
}
static void throwException(const char* msg){
m_thowFunc(msg);
}
};
extern "C" {
EXPORT void MyLibrary_setThrowFunction(void(*func)(const char*));
EXPORT void MyLibrary_foo();
}
我的图书馆.cpp
extern "C" {
EXPORT void MyLibrary_setThrowFunction(void(*func)(const char*)){
Thrower::setThrowFunction(func);
}
EXPORT void MyLibrary_foo(){
Thrower::throwException("oops, an error occured...");
}
}
在客户端代码中
void defaultThrowFunction(const char* msg){
throw std::runtime_error(msg);
}
int main(){
MyLibrary_setThrowFunction(&defaultThrowFunction);
try{
MyLibrary_foo();
}catch(std::runtime_error& e){
//handle exception
}
}
这就像一个魅力。我可以在客户端代码中处理DLL抛出的异常(其实是客户端代码抛出的)。我知道的唯一缺点是我在编译 DLL 时收到大量警告,因为“并非所有控制路径都返回一个值”...
我在这里遗漏了什么吗?这真的是个好主意吗?
最佳答案
这可能有效,但前提是两个代码库的抛出机制和堆栈展开代码基本相同且兼容。
为了在抛出后销毁它应该销毁的每个对象,客户端代码必须能够理解 DLL 代码如何设置其堆栈以及它在何处注册要清理的析构函数等。它可能是如果您幸运的话,您的客户端和 DLL 代码编译器充分同意此操作的情况。
哪种破坏了你设计的重点。
一种可能有效的方法是仔细编码 DLL 边界上的异常。
DLL 的“C”API 返回有关抛出的异常(如果有)的信息。客户端编译的仅 C++ 头文件包装器调用“C”API,并在客户端编译的代码中检测到异常、解包并抛出异常。
在 DLL 内部,“C”API 执行 try{}catch(){}
,并调用内部 C++ 库。 catch
子句将异常信息填充到“C”API 返回值中,然后返回。
现在抛出内部异常,在 C++ DLL 中捕获,在“C”API 中通过 DLL 边界进行编码,在客户端代码端打包回异常,然后重新抛出。
关于c++ - 这个 "trick"跨 DLL 边界抛出异常是个坏主意吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30760348/