使用动态库时,我知道我们应该只跨越边界传递普通旧数据结构。那么我们可以将指针传递给base吗?
我的想法是应用程序和库都可以知道一个公共接口(纯虚方法,= 0)。 库可以实例化该接口的子类型, 应用程序可以使用它。
例如,以下代码段安全吗?
// file interface.h
class IPrinter{
virtual void print(std::string str) = 0;
};
-
// file main.cpp
int main(){
//load plugin...
IPrinter* printer = plugin_get_printer();
printer->print( std::string{"hello"} );
}
-
// file plugin.cpp (compiled by another compiler)
IPrinter* plugin_get_printer(){
return new PrinterImpl{};
}
答案 0 :(得分:1)
类中存在虚函数意味着您的类将具有vtable,不同的编译器以不同方式实现vtables。
因此,如果你在DLL调用中使用带有虚方法的类,而另一方使用的编译器与你正在使用的编译器不同,那么结果可能是引人注目的崩溃。
在您的情况下,DLL创建的PrinterImpl
将以某种方式构建vtable,但printer->print()
中的main()
调用将尝试解释{的vtable {1}}以不同的方式解析IPrinter
方法调用。
答案 1 :(得分:1)
此代码段不安全:
DLL边界的两边不使用相同的编译器。这意味着name mangling(对于函数名称)和vtable布局(对于虚函数)可能不相同(特定于实现。
双方的堆也可能以不同方式进行管理,因此如果在DLL中没有完成,则会有与删除对象相关的风险。
这个article很好地展示了二进制兼容接口的主要挑战。
然而,你可以将指针作为POD的一部分传递到镜像的另一侧,只要另一部分不通过iself使用它(f.ex:你的app将一个指向配置对象的指针传递给DLL。稍后另一个DLL函数返回指向你的应用程序的指针。然后你的应用程序可以按预期使用它(至少如果它不是指向不再存在的本地对象的指针)。