cross-dll和智能指针

本文探讨在大型项目中模块间数据传递效率问题,特别关注跨DLL问题及解决方案,提出使用boost智能指针提升性能。讨论了智能指针在封装对象时的注意事项及如何避免内存管理冲突,并通过实例分析智能指针的应用限制与优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来源:http://flintning.blog.sohu.com/117761263.html

最近在做一个项目,存在大量的模块(exe或dll)间数据传递,希望避免频繁的数据复制降低处理效率,即一个模块创建的数据指针可以直接传递给另一个模块。

首先考虑的就是所谓的cross-dll问题,即一个模块分配的内存不应该由另一个模块释放,因为两个模块可能使用不同版本的C运行期库,甚至不使用C运行期库。关于这一点,windows核心编程中有说明,但并没有详细阐述原因,不过csdn上A Programming Bug对此有一段很精彩的阐述,摘录如下:

(http://dev.youkuaiyun.com/author/houdy/9f4bb2dc376d437787032971ee0eff97.html)

四.malloc/free
   这两个函数是使用频率最高的两个函数,由于他们是标准C库中的一部分,所以具有极高的移植性。这里的"移植性"指的是使用他们的代码可以在不同的平台下编译通过,而不同的平台下的C Run-Time Library的具体实现是平台相关的,在Windows平台的C Run-Time Library中的malloc()和free()是通过调用Heap Memory API来实现的。值得注意的是C Run-Time Library拥有独立的Heap对象,我们知道,当一个应用程序初始化的时候,首先被初始化的是C Run-Time Library,然后才是应用程序的入口函数,而Heap对象就是在C Run-Time Library被初始化的时候被创建的。对于动态链接的C Run-Time Library,运行库只被初始化一次,而对于静态连接的运行库,每链接一次就初始化一次,所以对于每个静态链接的运行库都拥有彼此不同的Heap 对象。这样在某种情况下就会出问题,导致程序崩溃,例如一个应用程序调用了多个DLL,除了一个DLL外,其他的DLL,包括应用程序本身动态连接运行库,这样他们就使用同一个Heap对象。而有一个DLL使用静态连接的运行库,它就拥有一个和其他DLL不同的Heap 对象,当在其他DLL中分配的内存在这个DLL中释放时,问题就出现了。

也就是说,两个都使用动态运行期库的模块(exe或dll)之间不存在cross-dll问题,而使用静态运行期库的模块,与其它模块之间,即使也是使用静态运行期库的模块,总是存在cross-dll问题的。

解决此问题的最佳方案应该是使用boost提供的shared_ptr智能指针,由于在创建时记录了所封装对象的deleter(析构函数),因此保证了智能指针对象时总是在创建对象的模块中被释放。另一个好处智能指针的资源计数使得多个使用者可以放心地共享资源,不用担心可能会被另一个模块释放。

不过还是存在不少问题,比如下面的例子:

class TestData

{

public:

  std::vector<int> DataArray;

//boost::shared_ptr<std::vector<int> > DataArray;   //成员对象需要封装吗?

}

typedef boost::sharded_ptr<TestData> HDATA;

DLL导出函数

HDATA GetDataArray();

智能指针在创建对象时记录了TestData对象的析构函数指针,一开始的疑问是DataArray成员会在什么地方析构?是不是也需要封装呢?C++ Primary只是说析构函数的调用顺序为:

1)派生类析构函数,2)成员类析构函数, 3)基类析构函数

并没有指出调用关系,如果编译器分别调用上述析构函数,那么就必须也封装成员对象,这样智能指针的用途就受到极大限制。反编译了生成的代码,才发现成员类和基类析构函数其实是在派生类析构函数中调用的,这样智能指针在封装对象的时候,完全不需要考虑对象的实现细节,只要对象析构函数保证正确释放资源。

第二个问题是,如果模块A调用模块B的GetDataArray函数获得了HDATA对象,那么模块A中能够向DataArray中添加数据吗?测试结果,答案是否定的。如果模块A执行

HDATA spData = GetDataArray();

spData->DataArray.push_back(10);

如果模块A或B中任何一个使用静态运行期库,就会抛出异常:

Invalid Address specified to RtlValidateHeap( 003B0000, 00032BD8 )
Windows 已在 TestSP.exe 中触发一个断点。

其原因可能是堆被损坏,这也说明 TestSP.exe 中或它所加载的任何 DLL 中有 bug。

这是因为vector在push_back时可能会存在内存分配和删除,这些操作不在share_ptr控制之下,这就导致模块A对模块B的运行期库Heap对象进行操作。

因此,前面的GetDataArray应该改成

typedef boost::sharded_ptr<TestData const> HDATA;

HDATA GetDataArray();

即模块A不应该对TestData有任何写操作,智能指针封装的对象应当看成一种只读资源,即一种“创建-只读访问-释放”的处理模式。

下面应该研究一下这样的智能指针

boost::shared_ptr<Y* y, D d, A a>

A是一个Allocator,不知道能不能解决上面的问题,不过“创建-只读访问-释放”模式看起来很干净,也没有资源对象访问的线程同步的问题,已经能够适应大多数情况下的要求了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值