c++ 插件:可以传递多态对象吗?
c++ plugin : Is it ok to pass polymorphic objects?
使用动态库时,我知道我们应该只跨边界传递普通旧数据结构。那么我们可以传递一个指向 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{};
}
你的 class 中存在虚函数意味着你的 class 将有一个 vtable,不同的编译器以不同的方式实现 vtable。
因此,如果您在 DLL 调用中使用带有虚拟方法的 classes,而另一端使用的编译器与您正在使用的编译器不同,结果很可能是严重的崩溃。
在你的例子中,由 DLL 创建的 PrinterImpl
将有一个以特定方式构造的 vtable,但你的 main()
中的 printer->print()
调用将尝试解释 vtable IPrinter
以不同的方式解决 print()
方法调用。
此代码段不安全:
您的 DLL 边界的两侧不使用相同的编译器。这意味着 name mangling (for function names) and the vtable 布局(对于虚函数)可能不相同(特定于实现。
两侧的堆也可能以不同的方式管理,因此如果不在 DLL 中删除对象,则存在与删除对象相关的风险。
这个 article 很好地展示了二进制兼容接口的主要挑战。
然而,您可以将指针作为 POD 的一部分传递到镜像的另一侧,只要另一部分不自行使用它即可(f.ex:您的应用将指针传递给DLL 的配置对象。稍后另一个 DLL 函数 returns 指向您的应用程序。然后您的应用程序可以按预期使用它(至少如果它不是指向不再存在的本地对象的指针)。
使用动态库时,我知道我们应该只跨边界传递普通旧数据结构。那么我们可以传递一个指向 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{};
}
你的 class 中存在虚函数意味着你的 class 将有一个 vtable,不同的编译器以不同的方式实现 vtable。
因此,如果您在 DLL 调用中使用带有虚拟方法的 classes,而另一端使用的编译器与您正在使用的编译器不同,结果很可能是严重的崩溃。
在你的例子中,由 DLL 创建的 PrinterImpl
将有一个以特定方式构造的 vtable,但你的 main()
中的 printer->print()
调用将尝试解释 vtable IPrinter
以不同的方式解决 print()
方法调用。
此代码段不安全:
您的 DLL 边界的两侧不使用相同的编译器。这意味着 name mangling (for function names) and the vtable 布局(对于虚函数)可能不相同(特定于实现。
两侧的堆也可能以不同的方式管理,因此如果不在 DLL 中删除对象,则存在与删除对象相关的风险。
这个 article 很好地展示了二进制兼容接口的主要挑战。
然而,您可以将指针作为 POD 的一部分传递到镜像的另一侧,只要另一部分不自行使用它即可(f.ex:您的应用将指针传递给DLL 的配置对象。稍后另一个 DLL 函数 returns 指向您的应用程序。然后您的应用程序可以按预期使用它(至少如果它不是指向不再存在的本地对象的指针)。