Dll导出构造函数有导致堆损坏的风险
Dll exporting a constructor risks causing heap corruption
我正在研究一个插件系统,该系统允许用户以DLL文件的形式开发自己的模块。模块应该使用由应用程序的所有组件导入的DLL中定义的对象。下面是一个示例对象的样子:
#include <boost/system/api_config.hpp>
#if defined BOOST_WINDOWS_API
#ifdef EXPORT
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
#else
#define API
#endif
class A
{
public:
API A();
API virtual ~A();
};
所有dll都是静态构建的(使用它们自己的CRT),并且具有完全相同的编译标志。我知道通过DLL边界交换对象可能会很麻烦,所以我几乎在任何地方都使用boost::shared_ptr
。但是,对象构造函数有一个困难:如果我在堆栈上(从不同的DLL)创建对象,一切都按预期工作。但是如果我使用new
操作符,当对象被删除时堆就会损坏。
A a; // Works fine, no problem when the object goes out of scope.
A* b = new A();
delete b; // Causes heap corruption!
这个问题的正确解决方法是什么?我觉得如果我必须在对象的DLL(如A* A::create() { return new A(); }
)中定义方法,代码将不太可读。在最坏的情况下,我正在考虑使new
操作符私有,以确保用户不会使用它。
根据你对我评论的回应:/MT
和/MTd
没有可以很好地使用dll(即使它们是默认的)。如果你想要使用dll和动态分配,必须使用/MD
或/MDd
。当您使用/MT
或/MTd
时,您可以有效地告诉系统为每个DLL使用单独的堆。也就是说在一个文件中进行分配,在另一个文件中进行删除,将破坏堆。当析构函数为虚函数时,实际的delete
将在析构函数中,而不是delete
表达式中的。(实际的问题是malloc
和free
,由operator new()
和operator delete()
函数
operator new()
和operator
delete()
成员,它们只转发给malloc
和free
。(当然,在operator new
的情况下,您必须检查你从malloc
得到的指针不是空的,抛出一个std::bad_alloc
(如果是)
但是这些都是不应该的情况下的变通方法存在。一切工作正常与/MD
或/MDd
,这是你应该使用什么(即使这意味着你不能合法使用)在没有许可证的机器上部署调试版本
我认为这个问题可能与您正在混合堆的事实有关。当您构建带有所有CRT静态链接的DLL时,这意味着它维护自己的堆。但是,来自主机进程的命令new
和delete
正在使用进程堆。我认为这种配置会引起问题。我认为最好的方法是添加两个方法到您的DLL: CreateA()
和DestroyA()
,并仅使用它们分配/销毁堆对象从DLL a
解决方案就是永远不要从DLL导出构造函数。而是导出一个工厂函数。永远不要在使用具体类时导出它。只导出纯抽象类。无论如何,对于减少耦合和所有相关的好东西来说,这是一个很好的样式。
- "error: no matching function for call to"构造函数错误
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 动态构造函数中的新字符 [] 抛出"损坏的顶部大小";
- 构造函数初始化和对象损坏
- 动态分配时类构造函数中的堆损坏
- 在使用新操作员和C 中的结构的调用构造函数时,获得内存损坏(Malloc)
- 在向量中使用不带复制且没有 noexcept 移动构造函数的对象.实际损坏的内容以及我如何确认它
- 在构造函数中使用std::vector导致内存损坏
- 复制构造函数和重载赋值运算符的堆损坏错误
- C++ 异常的双重释放损坏错误(复制构造函数不起作用)
- 用错误的“”调用构造函数;这个“;指针.这是堆栈损坏吗
- 构造函数中的字段初始化会损坏内存
- c++构造函数中的损坏
- Dll导出构造函数有导致堆损坏的风险
- c++双精度释放或损坏(out):即使使用复制构造函数和赋值操作符
- 从复制构造函数外部修改对象成员时导致向量内存损坏,但从复制构造函数内部修改时不会
- std::string构造函数中的内存分配/堆损坏