再谈Win32动态库的接口中使用STL(原创)

本文探讨了在Win32动态库接口中使用STL可能导致的问题,由于每个动态库有自己的静态数据段,导致STL容器在不同动态库间的使用成为问题。作者提出通过自定义空间分配器,利用系统堆内存管理来解决STL的运行时库依赖,以实现跨动态库的STL容器无限制传递。文章提供了简单的自定义分配器代码示例。

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

饿很少写东西,原因很多,比如懒,水平低,智商低,动手能力低.......
而饿还是要写这个帖子的原因是看到网上有部分关于Win32动态库的接口中使用STL的帖子内容有误,会误导大家.所以...........
如果哪位想传载本文,悉听尊便,如果能保留本文出处饿会很感谢.
http://kenny-office.blog.163.com/blog/static/307869272010010028561/
2010-1-1 00:13 严重厚道

STL很好用,但它不合适用于动态库的接口,原理很简单,每个动态库有独立的静态数据段,这个数据段对动态库间传递的STL容器是个灾难.M$给大家的解决方案是使用MD模式的代码生成.但这样必定限定你的STL窗口依赖VC的运行时库来运行你的程序.这个方式似乎不够优雅.有没有更好的方法呢?
答案当然是肯定的,人有多大胆地有多高产. 不过现在时间少人又懒就简单说明,如果后面有时间饿再完善(但饿还是比较负责任的说明一下估计是不会再完善了:->).
解决STL对运行时库依赖的关键点在STL默认的空间分配器,这个空间分配器的实现有静态成员.这些静态成员导致你的STL程序内的静态成员在不同动态库间无法寻址正确的数据区.
只要你写一个自己的空间分配器,直接使用系统的堆内存管理实现分配器就可以了解决这个问题.如果你还需要高效内存管理也可以封装一个内存池(内存池的库很多,boost里就有一个现成的),在你的空间分配器中使用接口透明掉内存池的实现.这样就可以使STL在动态库间不受限制的传递并保证内存管理的效率.
最后再说一下估计看到这里的大多数朋友是不知道怎么实现一个空间分配器的,饿给你一个满足最最最基本需求的版本,哈哈!
从MinGW带的STL实现里复制一个默认空间分配器来修改一下,具体怎么改因为太简单也不详细说了.你直接COPY下面的代码到你的代码里稍加调试就可以用了.但要提醒你这个示例的性能很一般,用于满足最最最基本需求的.

Just do it:

//
// 请把下面的代码另存为custom_alloc.hpp文件
//
namespace nsCustom
{
 using std::size_type; //如果size_type不是定义在std空间的就去掉,饿是个懒得追究细节的人.请各位看官看在饿写辛苦写本文情由下给饿这恶习一点点谅解.

 //

 struct TAlloc
 {
  static void* allocate( size_type siz )
  {
#if defined( _WIN_VER ) //如果没记错的话有个这样的宏判断在什么系统的.
#error 因为在M$VC下malloc是个宏,debug下被定义成的带堆跟踪的分配,工作会不正常所以用这个分配内存吧,具体怎么用饿就不帮你查MSDN了,毕竟饿不是M$专职程序员,估计你对这个比饿要熟.
   return (void*)GlobalAlloc( ... );
#else
   return malloc( siz );
#endif
  }

  static void deallocate( void* p, size_type siz )
  {
#if defined( _WIN_VER ) //如果没记错的话有个这样的宏判断在什么系统的.
   GlobalFree( p );
#else
   free( p );
#endif
  }
 };

 //
 /**
 *  @brief  The "standard" allocator, as per [20.4].
 *
 *  The private _Alloc is "SGI" style.  (See comments at the top
 *  of stl_alloc.h.)
 *
 *  The underlying allocator behaves as follows.
 *    - __default_alloc_template is used via two typedefs
 *    - "__single_client_alloc" typedef does no locking for threads
 *    - "__alloc" typedef is threadsafe via the locks
 *    - __new_alloc is used for memory requests
 *
 *  (See @link Allocators allocators info @endlink for more.)
 */
 template<typename _Tp>
 class allocator
 {
  typedef TAlloc _Alloc;          // The underlying allocator.(把默认的分配器替换成你上面实现的).
 public:
  typedef size_t     size_type;
  typedef ptrdiff_t  difference_type;
  typedef _Tp*       pointer;
  typedef const _Tp* const_pointer;
  typedef _Tp&       reference;
  typedef const _Tp& const_reference;
  typedef _Tp        value_type;

  template<typename _Tp1>
  struct rebind
  { typedef allocator<_Tp1> other; };

  allocator() throw() {}
  allocator(const allocator&) throw() {}
  template<typename _Tp1>
  allocator(const allocator<_Tp1>&) throw() {}
  ~allocator() throw() {}

  pointer
  address(reference __x) const { return &__x; }

  const_pointer
  address(const_reference __x) const { return &__x; }

  // NB: __n is permitted to be 0.  The C++ standard says nothing
  // about what the return value is when __n == 0.
  _Tp*
  allocate(size_type __n, const void* = 0)
  {
   _Tp* __ret = 0;
   if (__n)
   {
    if (__n <= this->max_size())
     __ret = static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp)));
    else
     __throw_bad_alloc();
   }
   return __ret;
  }

  // __p is not permitted to be a null pointer.
  void
  deallocate(pointer __p, size_type __n)
  { _Alloc::deallocate(__p, __n * sizeof(_Tp)); }

  size_type
  max_size() const throw() { return size_t(-1) / sizeof(_Tp); }

  void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }
  void destroy(pointer __p) { __p->~_Tp(); }
 };

 //
 template<>
 class allocator<void>
 {
 public:
  typedef size_t      size_type;
  typedef ptrdiff_t   difference_type;
  typedef void*       pointer;
  typedef const void* const_pointer;
  typedef void        value_type;

  template<typename _Tp1>
  struct rebind
  { typedef allocator<_Tp1> other; };
 };

 //
 template<typename _T1, typename _T2>
 inline bool
 operator==(const allocator<_T1>&, const allocator<_T2>&)
 { return true; }

 template<typename _T1, typename _T2>
 inline bool
 operator!=(const allocator<_T1>&, const allocator<_T2>&)
 { return false; }

} //namespace nsCustom

 


//
///   DLL导出声明       //
//


#include <custom_alloc.hpp>

/**********************************************
* DLL Interface
*/
class __LIB_EXPOER_API__ ExportClass
{
 std::vector< long, nsCustom::allocator< long > > vec;
 std::list< ExportClass*, nsCustom::allocator< long > > lst;
};


//
///    ok, sir, try it   
//
void main()
{
 ExportClass ec;
 ec.vec.push_back( 3L );
 ec.lst.push_back( &ec );
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值