饿很少写东西,原因很多,比如懒,水平低,智商低,动手能力低.......
而饿还是要写这个帖子的原因是看到网上有部分关于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 );
}