我知道在一个dll中进行的内存分配然后随后在另一个dll中释放会导致各种问题,特别是关于CRT。在导出STL容器时,这些问题尤其成问题。我们之前遇到过这些问题(编写与我们的库链接的自定义Adobe插件时),我们通过定义我们在所有容器中使用的自己的分配器来解决这些问题,例如:
typedef std::vector < SessionFields,
OurAllocator < SessionFields > >
VectorSessionFields;
typedef std::set < SessionFields,
std::less < SessionFields >,
OurAllocator < SessionFields > >
SetSessionFields;
在向我们的代码传递类型时,这很有效,但是我们遇到了一个问题,我们现在不得不在Adobe的SDK中调用一个函数来返回一个填充的向量,当它出现时会导致崩溃范围。
显然,当我的代码中最终免费的Adobe属于不同堆的SDK中分配内存时出现问题。所以我想也许我可以做一些聪明的事情,比如以某种方式覆盖或导出SDK中使用的分配器,这样我就可以用它来清理从函数返回的容器。
我也在考虑编写一个包装器或某种类型的thunking层,从而可以在我的代码和SDK之间安全地编组STL容器(虽然听起来非常混乱)。
或者,我也在考虑使用GetProcessHeaps
来识别SDK中使用的堆,并尝试释放这个堆,而不是默认堆。
有没有人就如何解决这个问题提出任何建议?
答案 0 :(得分:8)
具有讽刺意味的是,Adobe Source Libraries有一个adobe::capture_allocator
类,专门针对这种DLL安全性编写。它的工作方式是捕获本地new
和delete
此时它被实例化,并在对象的生命周期中携带它们。 (有关如何执行此操作的详细信息,请参阅adobe::new_delete_t
,尤其是实现here。)使用捕获的delete
例程进行解除分配,保证无论您在何处删除适当的delete
。
您可以在Adobe源库中查看version_1
类型中使用的capture_allocator
,例如adobe::any_regular_t
和adobe::copy_on_write
。 capture_allocator
也应与所有STL容器类型兼容。
更新:capture_allocator
不符合标准,因为它保留了状态。这不应该是其可用性的一大障碍,但它确实意味着它的使用不能保证与符合标准的容器一起使用。
答案 1 :(得分:2)
目前我们正在开发一个通过C接口公开C ++功能的dll(为了C#能够使用上述dll)。
例如:dll有一个struct myStruct_s,该接口公开了以下函数:
<强> interface.h 强>
#ifndef INTERFACE_TYPES_H
# error Please include interace_types.h
#endif
myStruct_s * CreateTheStruct() { return new myStruct_s(); }
void DestroyTheStruct(myStruct_s * the_struct) { delete the_struct; }
void DoSomethingToTheStruct(myStruct_s * the_struct);
<强> interface_types.h 强>
#define INTERFACE_TYPES_H
struct myStruct_s; // fwd declaration
#endif
<强> interface.cpp 强>
#if defined(__CPPPLUS) || defined(__cplusplus) || defined (__CPLUSPLUS)
#include<TheRealFileContainingTheRealMyStruct_s.h>
// handle the .h's functions here
#endif
<强> comeOutsideCppFile.cpp 强>
#include "interface_types.h"
#include "interface.h"
void main()
{
myStuct_s * x = CreateTheStruct;
DoSomethingToTheStruct(x);
DestroyTheStruct(x);
}
以上是我们的工作原理的大致概述,基本上: 无论暴露的dll是什么:创建,处理,销毁dll-side
此代码不是100%准确!!!
另外,请记住,如果您使用的是纯C ++ DLL,则可能需要使用与用于构建dll的设置相同的设置编译器。
答案 2 :(得分:0)
您可能会尝试查看是否有任何正式的C ++规则,当在一个DLL中抛出异常并在另一个DLL中捕获然后超出范围时会发生什么 - 它看起来非常相似。对于例外,我认为你需要提供一个带有特殊签名的复制构造函数,尽管我现在还不确定它是什么。