-
STL stack allocate
添加时间:2013-6-16 点击量:游戏编程精华精辟3供给了一份栈分派器源代码:
#include <memory>
#include <limits>
template <typename T>
class StackAlloc
{
public:
// Typedefs
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T pointer;
typedef const T const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
// Constructors
StackAlloc() throw()
:
mpStack( NULL ),
mBytesAllocated( 0 ),
mMaxBytes( 0 )
{
}
StackAlloc( unsigned char pStack, size_t nMaxBytes ) throw()
:
mpStack( pStack ),
mBytesAllocated( 0 ),
mMaxBytes( nMaxBytes )
{
}
StackAlloc( const StackAlloc& sa ) throw()
:
mpStack( sa.mpStack ),
mBytesAllocated( 0 ),
mMaxBytes( sa.mMaxBytes )
{
// Copying the stack resets mBytesAllocated to zero
}
#if _MSC_VER >= 1400 // VC 7 cant handle template members
template <typename U>
StackAlloc( const StackAlloc<U>& sa ) throw()
:
mpStack( sa.mpStack ),
mBytesAllocated( 0 ),
mMaxBytes( sa.mMaxBytes )
{
// Copying the stack resets mBytesAllocated to zero
}
#endif
StackAlloc& operator=( const StackAlloc& sa )
{
// Copying the stack resets mBytesAllocated to zero
mpStack = sa.mpStack;
mBytesAllocated = 0;
mMaxBytes = sa.mMaxBytes;
return this;
}
// Destructor
~StackAlloc() throw()
{
}
// Utility functions
pointer address( reference r ) const
{
return &r;
}
const_pointer address( const_reference c ) const
{
return &c;
}
size_type max_size() const
{
return std::numeric_limits<size_t>::max() / sizeof(T);
}
// In-place construction
void construct( pointer p, const_reference c )
{
// placement new operator
new( reinterpret_cast<void>(p) ) T(c);
}
// In-place destruction
void destroy( pointer p )
{
// call destructor directly
(p)->~T();
}
// Rebind to allocators of other types
template <typename U>
struct rebind
{
typedef StackAlloc<U> other;
};
// Allocate raw memory
pointer allocate( size_type n, const void = NULL )
{
void pRaw = mpStack + mBytesAllocated;
mBytesAllocated += ( n sizeof(T) );
if( mBytesAllocated+1 > mMaxBytes )
throw std::bad_alloc();
return pointer(pRaw);
}
// Free raw memory.
// Note that C++ standard defines this function as
// deallocate( pointer p, size_type). Because Visual C++ 6.0
// compiler doesnt support template rebind, Dinkumware uses
// void hack.
void deallocate( void, size_type )
{
// No need to free stack memory
}
// Non-standard Dinkumware hack for Visual C++ 6.0 compiler.
// VC 6 doesnt support template rebind.
char _Charalloc( size_type n )
{
return reinterpret_cast<char>( allocate( n, NULL ) );
}
// Required for global comparison functions
unsigned char GetStack() const
{
return mpStack;
}
private:
unsigned char mpStack;
size_t mBytesAllocated;
size_t mMaxBytes;
}; // end of StackAlloc
// Comparison
template <typename T1>
bool operator==( const StackAlloc<T1>& lhs, const StackAlloc<T1>& rhs) throw()
{
return lhs.GetStack() == rhs.GetStack();
}
template <typename T1>
bool operator!=( const StackAlloc<T1>& lhs, const StackAlloc<T1>& rhs) throw()
{
return lhs.GetStack() != rhs.GetStack();
}
View Code测试发明在VS2012下编译运行,栈分派器在开释内存时失足。
原因是当用户供给自定义的分派器时,VS会保存一个分派策略对象来经管计数神马的。
项目组VS源代码如下:_Vector_alloc(const _Alty& _Al = _Alty())
: _Alval(_Al)
{ // construct allocator _Al
_Alloc_proxy();
}
//-------------------------------------------------------------
void _Alloc_proxy()
{ // construct proxy _Alval
typename _Alloc::template rebind<_Container_proxy>::other
_Alproxy(_Alval);
this->_Myproxy = _Alproxy.allocate(1);
_Alproxy.construct(this->_Myproxy, _Container_proxy());
this->_Myproxy->_Mycont = this;
}
View Codevector的栈分派器是_Alval,也就是用户供给的栈分派器。
分派策略对象_Myproxy占用的内存也是经由过程_Alval申请的。仅仅是如许也许不会呈现神马题目,可是_Myproxy是经由过程调用template <typename U> StackAlloc( const StackAlloc<U>& sa )重绑定函数从_Alval获取了一个新的分派器对象_Alproxy。此时_Alval与_Alproxy其实是共用一段内存的,而彼此不知道对方的存在。导致_Myproxy应用的内存在vector插入元素时被覆盖。当vector开释内存或者迁徙内存时须要开释掉_Myproxy的内存时法度就溃散了。
实际上游戏编程精华精辟3供给的stack allocate在语义上就存在题目,mpstack不该该是值语义的,因为stack allocate实际上即没有真正向体系申请内存,也并没有真正的开释内存,而只是代为经管一段底本就存在的内存。是以,mpstack应当是引用语义的。
现将本人批改后的代码献上:
PS:只在VS2012下测试了vector与list容器。
1 template<typename T>
2 class stack_alloc
3 {
4 public:
5 typedef size_t size_type;
6 typedef ptrdiff_t difference_type;
7 typedef T pointer;
8 typedef const T const_pointer;
9 typedef T& reference;
10 typedef const T& const_reference;
11 typedef T value_type;
12
13 public:
14 stack_alloc() throw()
15 : m_begin(NULL)
16 , m_cur(m_begin)
17 , m_max_bytes(0)
18 {
19 }
20
21 stack_alloc(uchar pstack, size_t max_bytes) throw()
22 : m_begin(pstack)
23 , m_cur(m_begin)
24 , m_max_bytes(max_bytes)
25 {
26 }
27
28 stack_alloc(const stack_alloc& sa) throw()
29 : m_begin(sa.m_begin)
30 , m_cur(sa.m_cur)
31 , m_max_bytes(sa.m_max_bytes)
32 {
33 }
34
35 #if _MSC_VER >= 1400 // VC 7 cant handle template members
36 template <typename U>
37 stack_alloc(const stack_alloc<U>& sa) throw()
38 : m_begin(sa.m_begin)
39 , m_cur(sa.m_cur)
40 , m_max_bytes(sa.m_max_bytes)
41 {
42 }
43 #endif
44
45 stack_alloc& operator=( const stack_alloc& rhs )
46 {
47 return this;
48 }
49
50 ~stack_alloc() throw()
51 {
52 }
53
54 public:
55 // Utility functions
56 pointer address( reference r ) const
57 {
58 return &r;
59 }
60
61 const_pointer address( const_reference c ) const
62 {
63 return &c;
64 }
65
66 size_type max_size() const
67 {
68 return m_max_bytes/sizeof(T);
69 }
70
71 // In-place construction
72 void construct( pointer p, const_reference c )
73 {
74 new( reinterpret_cast<void>(p) ) T(c);
75 }
76
77 // In-place destruction
78 void destroy( pointer p )
79 {
80 (p)->~T();
81 }
82
83 // Rebind to allocators of other types
84 template <typename U>
85 struct rebind
86 {
87 typedef stack_alloc<U> other;
88 };
89
90 // Allocate raw memory
91 pointer allocate( size_type n, const void = NULL )
92 {
93 void praw = m_cur;
94 m_cur += nsizeof(T);
95 if(m_cur+1>m_begin+m_max_bytes)
96 {
97 throw std::bad_alloc();
98 }
99
100 return pointer(praw);
101 }
102
103 void deallocate( void p, size_type n)
104 {
105 }
106
107 // Non-standard Dinkumware hack for Visual C++ 6.0 compiler.
108 // VC 6 doesnt support template rebind.
109 char _charalloc( size_type n )
110 {
111 return reinterpret_cast<char>( allocate( n, NULL ) );
112 }
113
114 unsigned char get_stack() const
115 {
116 return m_begin;
117 }
118
119 uchar& m_cur;
120 size_t m_max_bytes;
121 uchar m_begin;
122 };
123
124 template <typename T>
125 bool operator==( const stack_alloc<T>& lhs, const stack_alloc<T>& rhs) throw()
126 {
127 return lhs.get_stack() == rhs.get_stack();
128 }
129
130 template <typename T>
131 bool operator!=( const stack_alloc<T>& lhs, const stack_alloc<T>& rhs) throw()
132 {
133 return lhs.get_stack() != rhs.get_stack();
134 }
View Code
我们永远不要期待别人的拯救,只有自己才能升华自己。自己已准备好了多少容量,方能吸引对等的人与我们相遇,否则再美好的人出现、再动人的事情降临身边,我们也没有能量去理解与珍惜,终将擦肩而过。—— 姚谦《品味》