c++ DLL接口和内存

C++ DLL interface and memory

本文关键字:内存 接口 DLL c++      更新时间:2023-10-16

我的问题可能与这里和这里有关:Q如果我们在堆栈上创建另一个DLL中定义的类的类型实例,它是安全的吗?

// A DLL
class DLL_EXPORT Foo;

// Target exe
int main()
{
     // bad, not supposed to do this:
     Foo* x = get_instance_from_dll();
     delete x;
     // **Question**:
     // what about stack variable of type declared in the DLL?
     // is this alright?
     Foo x;
}

不,不安全。使用暴露c++代码的DLL有三个基本问题:

  • 使用不同分配器的DLL。所以delete不能破坏这个物体。

  • 你的编译器没有为类对象计算相同的布局。如果它的任何成员都是标准的c++库类,比如std::string或std::vector,问题就更大了。该DLL可能是用这些类的不同的版本编译的。与c++ 11之前的版本一样,它在std类实现中引起了许多变化。或者使用优化的版本构建设置,并且没有启用迭代器调试,而您启用了。

  • DLL可能抛出的跨模块边界的任何异常对象都会遇到上述两个问题。当您将DLL接口修复为安全时,这一点很容易被忽略,您不能轻松地对异常做同样的事情。

第二个项目是你的克星,你的编译器会为对象计算错误的大小,并且不会在堆栈框架上为它保留正确的空间。当实际对象大小较大时,DLL中的代码将覆盖堆栈上的其他变量,这尤其令人讨厌。很难诊断

据我所知,这里唯一的限制(因为内存管理)是new和delete必须由相同的模块调用(基本上,如果您在DLL中新建它,则在相同的DLL中删除它)。

如果你在堆栈上创建对象,这根本不是问题。

编辑:你问在构造函数中有new的情况:构造函数和析构函数将在DLL的空间中运行,所以只要new和delete在DLL中(大概在构造函数和析构函数中),那就不是问题。

也认为你应该非常认真地对待Hans的建议——如果两个编译中使用的头文件由于某种原因(不同的版本)而不同,或者模块是用不同的编译器编译的,或者编译器设置在某些方面不同,那么你很容易很难诊断bug。

如果你没有使用相同的工具构建两个模块并一起发布,你应该不会遇到任何问题。