为了账号安全,请及时绑定邮箱和手机立即绑定

如何安全地将对象(特别是STL对象)传递给DLL?

如何安全地将对象(特别是STL对象)传递给DLL?

慕姐8265434 2019-07-16 18:07:47
如何安全地将对象(特别是STL对象)传递给DLL?如何将类对象(特别是STL对象)传递给C+DLL?我的应用程序必须以dll文件的形式与第三方插件交互,而且我无法控制这些插件是用什么编译器构建的。我知道对于STL对象没有保证的ABI,我担心在我的应用程序中造成不稳定。
查看完整描述

3 回答

?
慕桂英3389331

TA贡献2036条经验 获得超8个赞

编写了一个很好的解释,解释了为什么在一般情况下,ABI的缺乏会阻止C+对象跨越DLL边界,即使类型定义处于用户控制之下,并且在两个程序中都使用完全相同的令牌序列。(有两种情况是可行的:标准布局类和纯接口)

对于在C+标准中定义的对象类型(包括那些来自标准模板库的对象类型),情况要糟糕得多。定义这些类型的令牌在多个编译器中并不相同,因为C+标准没有提供完整的类型定义,只提供最低要求。此外,出现在这些类型定义中的标识符的名称查找不会解决相同的问题。即使在存在C+ABI的系统上,试图跨模块边界共享此类类型也会由于一个定义规则的违反而导致大量未定义的行为。

这是Linux程序员不习惯处理的事情,因为g+的libstdc+实际上是一个标准,几乎所有的程序都使用它,从而满足了ODR.clang的libc+打破了这个假设,然后C+11伴随着几乎所有标准库类型的强制性更改。

只是不要在模块之间共享标准库类型。这是不确定的行为。


查看完整回答
反对 回复 2019-07-16
?
繁花如伊

TA贡献2012条经验 获得超12个赞

这里的一些答案使得通过C+类听起来真的很可怕,但我想分享另一个观点。其他一些响应中提到的纯虚拟C+方法实际上比您想象的要干净。我已经围绕这个概念建立了一个完整的插件系统,它已经运行了很多年了。我有一个“PluginManager”类,它使用LoadLib()和GetProcAddress()动态地从指定的目录加载dll(以及Linux等效文件,以便跨平台执行)。

信不信由你,即使您做了一些奇怪的事情,比如在纯虚拟界面的末尾添加一个新函数,并尝试在没有新函数的情况下加载针对接口编译的dll,这种方法也是可以原谅的-它们会加载得很好。当然.。您必须检查版本号,以确保您的可执行文件只对实现该函数的较新的dll调用新函数。但好消息是:它有效!因此,在某种程度上,你有一个粗糙的方法来逐步发展你的界面。

关于纯虚拟接口的另一件很酷的事情-你可以继承你想要的多少接口,你永远不会遇到钻石问题!

我想说,这种方法最大的缺点是,您必须非常小心您作为参数传递的类型。不首先用纯虚拟接口包装类或STL对象。没有结构(没有经过实用主义包装巫毒)。只是原始类型和指向其他接口的指针。此外,您不能超载函数,这是一个不便,但不是一个显示停止。

好消息是,使用少量代码行,您可以创建可重用的泛型类和接口来包装STL字符串、向量和其他容器类。或者,您可以将函数添加到您的接口中,如GetCount()和GetVal(N),以便让用户遍历列表。

人们为我们构建插件很容易。他们不必是ABI边界方面的专家-他们只是继承他们感兴趣的接口,对他们支持的函数进行编码,并为不支持的函数返回false。

据我所知,制造所有这些工作的技术并不是基于任何标准。据我所知,微软决定这样做他们的虚拟表,这样他们就可以制作COM,而其他编译器编写人员也决定效仿。这包括GCC、Intel、Borland和其他大多数主要的C+编译器。如果您计划使用一个晦涩的嵌入式编译器,那么这种方法可能不会适用于您。理论上说,任何一家编译器公司都可以随时改变他们的虚拟表并打破它们,但是考虑到多年来编写的大量代码依赖于这种技术,如果任何主要的参与者决定打破排名,我会感到非常惊讶。

所以这个故事的寓意是.。除了一些极端的情况外,您需要一个负责接口的人,他可以确保ABI边界与原始类型保持干净,并避免重载。如果您同意这一规定,那么我就不怕在编译器之间共享DLL/SOS中类的接口。直接共享类=麻烦,但共享纯虚拟接口并不那么糟糕。


查看完整回答
反对 回复 2019-07-16
  • 3 回答
  • 0 关注
  • 578 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信