鉴于:Executable使用dll。它们具有不同的c / c ++运行时。它们之间的接口有哪些限制? 除了他们使用相同的编译器,相同的Boost版本(但不同的预编译的升压库)。
据我所知,不同的运行时可以有不同的堆。因此,delete必须与同一堆中的new对应。
最重要的是我们无法通过接口STL对象传递,因为当我们构建exe时,STL对象与一个运行时链接 当构建dll时,同一个对象(如果我们通过引用传递它或通过接口复制)将与另一个运行时链接。 另一个运行时可以具有该对象的不同实现。
让我们考虑一下案例:
我认为以下是安全的。 Dll导出具有参数的函数:对包含私有STL类作为成员的导出用户定义类的引用。 Dll为此对象分配内存。当想要删除它时,Exe调用此对象的Release方法。
我认为以下内容并不安全。用户定义的类在exe中实例化并通过exe / dll接口传递。 此类包含私有STL类作为成员。 exe和dll共享此用户类的头文件/实现文件。 当此类在单独的项目中构建时,将使用不同的STL实现。例如,不同的实现 string :: size()(来自不同的运行时)将应用于内存中的同一对象。
我认为以下是安全的。用户定义的类在exe中实例化并通过exe / dll接口传递。 该类不依赖于标准库,它只使用原始C ++类型。 exe和dll共享此用户类的头文件/实现文件。 此外,我们必须控制new和delete对应于同一个堆。例如,我们可以重载new / delete,因此它们使用:: GetProcessHeap。
我认为以下是不安全的:通过exe / dll接口传递boost对象,因为它们可以依赖于标准库类。删除也可能与新的堆不对应。
我认为以下是不安全的:即使我们通过exe / dll接口传递boost对象并且它们不依赖于标准库类但不是仅作为头文件实现 - 而是可以创建对象使用一个boost lib(用于一个运行时)并与另一个boost lib一起使用(用于另一个运行时)。删除也可能与新的堆不对应。
此外,我想使用一些智能指针来传递对象(在第3项中提到)从exe到dll以及从dll到exe的引用。 我认为这个智能指针也应该重载new / delete以从默认进程堆分配引用计数器。 当它试图删除指向对象时,它将调用由该对象重载的删除(如第3项所述)
对于第1项中的对象,我想使用自定义智能指针,它将调用指向对象的释放方法 (作为自定义版本的boost :: shared_ptr)
没有提到哪些问题?请纠正我。
答案 0 :(得分:5)
您的问题的一般答案是:如果实际执行的操作不依赖于运行时,则对从EXE / DLL接收的对象执行某些操作是安全的。例如。 vtable调用,函数指针调用,DLL的显式函数调用。
依赖于运行时的东西(来自头文件的内联方法,任何对STL对象布局做出任何假设的东西等)都是不安全的。
回到你的例子:
如果调用Release()方法,则应该小心并确保从DLL调用Release()的实现,而不是编译器生成EXE文件所创建的另一个实现。确保它的最简单方法是使Release()成为虚拟的,这样调用总是使用vtable中的方法指针调用(由DLL提供)。
是的,来自STL的内联方法如string :: size()会在这里引起问题。
说明:
有一些低概率的事情可能导致上面没有提到的问题:
总结一下,建议查看Microsoft COM中的实现方式并设计类似的东西。即将EXE / DLL交互限制为:
简单明确的结构。确保所有编译器的对齐选项匹配。如果你想使用非平凡的结构,并且你使用不同的编译器,最好是偏执,并把这样的检查:
struct MyStruct
{
...
};
C_ASSERT(sizeof(MyStruct) == ...);
C_ASSERT(FIELD_OFFSET(MyStruct, MyMember) = ... );
类似C函数传递和/或返回指向接口的指针。