Recently, I checked the content of the Space configurator and implemented the ACE_Allocator class of ACE, The allocator class implementation of SGI, And the allocator Implementation of MS. I also referred to Mr Hou Jie's STL source code analysis. there are many gains.
I have heard that there is a file indicating that allocator in STL implements the standard, but I have not found it. According to my experiment, the standard allocator needs to implement rebind, allocate, deallocate, max_size and constructor have six functions. That is to say, to write a allocator available in the standard vector, you only need to implement the above interfaces.
Let's talk about Microsoft's allocator. The file name is xmemory. I think it is the least informative. It is basically the encapsulation of new and delete, which is made to cater to the standard of the C ++ standard library. There is no skill, let alone a subtle one. The above six interfaces are implemented below.
[Cpp]
// Template class allocator
Emplate <class _ Ty>
Class allocator
: Public _ Allocator_base <_ Ty>
{// Generic allocator for objects of class _ Ty
Ublic:
Typedef _ Allocator_base <_ Ty> _ Mybase;
Typedef typename _ Mybase: value_type;
Typedef value_type _ FARQ * pointer;
Typedef value_type _ FARQ & reference;
Typedef const value_type _ FARQ * const_pointer;
Typedef const value_type _ FARQ & const_reference;
Typedef _ SIZT size_type;
Typedef _ PDFT difference_type;
Template <class _ Other>
Struct rebind
{// Convert an allocator <_ Ty> to an allocator <_ Other>
Typedef allocator <_ Other> other;
};
Pointer address (reference _ Val) const
{// Return address of mutable _ Val
Return (& _ Val );
}
Const_pointer address (const_reference _ Val) const
{// Return address of nonmutable _ Val
Return (& _ Val );
}
Allocator () _ THROW0 ()
{// Construct default allocator (do nothing)
}
Allocator (const allocator <_ Ty> &) _ THROW0 ()
{// Construct by copying (do nothing)
}
Template <class _ Other>
Allocator (const allocator <_ Other> &) _ THROW0 ()
{// Construct from a related allocator (do nothing)
}
Template <class _ Other>
Allocator <_ Ty> & operator = (const allocator <_ Other> &)
{// Assign from a related allocator (do nothing)
Return (* this );
}
Void deallocate (pointer _ Ptr, size_type)
{// Deallocate object at _ Ptr, ignore size
: Operator delete (_ Ptr );
}
Pointer allocate (size_type _ Count)
{// Allocate array of _ Count elements
Return (_ Allocate (_ Count, (pointer) 0 ));
}
Pointer allocate (size_type _ Count, const void _ FARQ *)
{// Allocate array of _ Count elements, ignore hint
Return (allocate (_ Count ));
}
Void construct (pointer _ Ptr, const _ Ty & _ Val)
{// Construct object at _ Ptr with value _ Val
_ Construct (_ Ptr, _ Val );
}
Void destroy (pointer _ Ptr)
{// Destroy object at _ Ptr
_ Destroy (_ Ptr );
}
_ SIZT max_size () const _ THROW0 ()
{// Estimate maximum array size
_ SIZT _ Count = (_ SIZT) (-1)/sizeof (_ Ty );
Return (0 <_ Count? _ Count: 1 );
}
};
2. allocator implemented by sgi stl. The STL implementation version, which is promoted by C ++ authors, is of course compliant with the standard. Its main site: http://www.sgi.com/tech/stl/, how to configure debugging I have talked about in the previous article. Its implementation has gained a deeper understanding by reading Mr Hou Jie's book. Of course, the code is somewhat different from the version parsed by Mr. Hou. It is nothing more than adding some agents and packaging, which has little impact. We can see that most of these interfaces are implemented through functions in _ sgi_alloc.
[Cpp]
Template <class _ Tp>
Struct _ stlport_class
{Typedef _ Tp _ Type ;};
Template <class _ Tp>
Class allocator //: public _ AllocatorAux <_ Tp>
/* A small helper struct to recognize STLport allocator implementation
* From any user specialization one.
*/
: Public _ stlport_class <allocator <_ Tp>
{
Public:
Typedef _ Tp value_type;
Typedef _ Tp * pointer;
Typedef const _ Tp * const_pointer;
Typedef _ Tp & reference;
Typedef const _ Tp & const_reference;
Typedef size_t size_type;
Typedef ptrdiff_t difference_type;
# If defined (_ STLP_MEMBER_TEMPLATE_CLASSES)
Template <class _ Tp1> struct rebind {
Typedef allocator <_ Tp1> other;
};
# Endif
Allocator () _ STLP_NOTHROW {}
# If defined (_ STLP_MEMBER_TEMPLATES)
Template <class _ Tp1> allocator (const allocator <_ Tp1> &) _ STLP_NOTHROW {}
# Endif
Allocator (const allocator <_ Tp> &) _ STLP_NOTHROW {}
# If! Defined (_ STLP_NO_MOVE_SEMANTIC)
Allocator (_ move_source <allocator <_ Tp> src) _ STLP_NOTHROW {}
# Endif
~ Allocator () _ STLP_NOTHROW {}
Pointer address (reference _ x) const {return & __x ;}
Const_pointer address (const_reference _ x) const {return & __x ;}
// _ 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 ){
If (_ n> max_size ()){
_ STLP_THROW_BAD_ALLOC;
}
If (_ n! = 0 ){
Size_type _ buf_size = _ n * sizeof (value_type );
_ Tp * _ ret = _ REINTERPRET_CAST (_ Tp *, _ sgi_alloc: allocate (_ buf_size ));
# If defined (_ STLP_DEBUG_UNINITIALIZED )&&! Defined (_ STLP_DEBUG_ALLOC)
Memset (char *) _ ret, _ STLP_SHRED_BYTE, _ buf_size );
# Endif
Return _ ret;
}
Return 0;
}
// _ P is permitted to be a null pointer, only if n = 0.
Void deallocate (pointer _ p, size_type _ n ){
_ STLP_ASSERT (_ p = 0) = (_ n = 0 ))
If (_ p! = 0 ){
# If defined (_ STLP_DEBUG_UNINITIALIZED )&&! Defined (_ STLP_DEBUG_ALLOC)
Memset (char *) _ p, _ STLP_SHRED_BYTE, _ n * sizeof (value_type ));
# Endif
_ Sgi_alloc: deallocate (void *) _ p, _ n * sizeof (value_type ));
}
}
# If! Defined (_ STLP_NO_ANACHRONISMS)
// Backwards compatibility
Void deallocate (pointer _ p) const {if (_ p! = 0) _ sgi_alloc: deallocate (void *) _ p, sizeof (value_type ));}
# Endif
Size_type max_size () const _ STLP_NOTHROW {return size_t (-1)/sizeof (value_type );}
Void construct (pointer _ p, const_reference _ val) {_ STLP_STD: _ Copy_Construct (_ p, _ val );}
Void destroy (pointer _ p) {_ STLP_STD: _ Destroy (_ p );}
# If defined (_ STLP_NO_EXTENSIONS)
/* STLport extension giving rounded size of an allocated memory buffer
* This method do not have to be part of a user defined allocator implementation
* And won't even be called if such a function was granted.
*/
Protected:
# Endif
_ Tp * _ M_allocate (size_type _ n, size_type & _ allocated_n ){
If (_ n> max_size ()){
_ STLP_THROW_BAD_ALLOC;
}
If (_ n! = 0 ){
Size_type _ buf_size = _ n * sizeof (value_type );
_ Tp * _ ret = _ REINTERPRET_CAST (_ Tp *, _ sgi_alloc: allocate (_ buf_size ));
# If defined (_ STLP_DEBUG_UNINITIALIZED )&&! Defined (_ STLP_DEBUG_ALLOC)
Memset (char *) _ ret, _ STLP_SHRED_BYTE, _ buf_size );
# Endif
_ Allocated_n = _ buf_size/sizeof (value_type );
Return _ ret;
}
Return 0;
}
# If defined (_ STLP_USE_PARTIAL_SPEC_WORKAROUND )&&! Defined (_ STLP_FUNCTION_TMPL_PARTIAL_ORDER)
Void _ M_swap_workaround (allocator <_ Tp> & _ other ){}
# Endif
};
During debugging, I used the memory allocation function _ M_allocate to access the memory pool (according to Mr. Hou, It is space, not necessarily memory) to the free chain and return to the user. To learn more, you must go to the source code: RTFSC. Summary: The SGI Code conforms to the standards and standards. Combined with Mr. Hou's book, you can see the essence of STL implementation.
3. Finally, let's talk about the allocator Implementation of ACE. It should be said that the implementation of ACE may not follow the C ++ standard library standards during the design, but only for efficient and secure use within ACE. We can also look at the following interface code. The base class ACE_Allocator directly uses malloc and free for subclass implementation. This code can be fully combined with Mr. Hou's book, but with the ACE or _ S prefix before some implementations, the implementation principle is very similar to SGI. In terms of memory block management, small memory segments (less than 128) are also managed using free links, and large memory segments (greater than 128) are directly allocated. In terms of free linked list, it also uses the same tips as SGI, that is, to place the next pointer at the beginning of a memory block that is not used (this is the first time I saw this trick, it's a little strange, but it can be implemented very well, mainly because the efficiency is improved and the quantity is not refined ). A block chain is added to SGI for more flexible use (it should be limited to ACE applications because it does not comply with standards ).
[Cpp]
Class ACE_Export ACE_Allocator
{
Public:
/// Unsigned integer type used for specifying memory block lengths.
Typedef size_t size_type;
// = Memory Management
/// Get pointer to a default ACE_Allocator.
Static ACE_Allocator * instance (void );
/// Set pointer to a process-wide ACE_Allocator and return existing
/// Pointer.
Static ACE_Allocator * instance (ACE_Allocator *);
/// Delete the dynamically allocated Singleton
Static void close_singleton (void );
/// "No-op" constructor (needed to make certain compilers happy ).
ACE_Allocator (void );
/// Virtual destructor
Virtual ~ ACE_Allocator (void );
/// Allocate @ a nbytes, but don't give them any initial value.
Virtual void * malloc (size_type nbytes) = 0;
/// Allocate @ a nbytes, giving them @ a initial_value.
Virtual void * calloc (size_type nbytes, char initial_value = '\ 0') = 0;
/// Allocate <n_elem> each of size @ a elem_size, giving them
/// @ A initial_value.
Virtual void * calloc (size_type n_elem,
Size_type elem_size,
Char initial_value = '\ 0') = 0;
/// Free <ptr> (must have been allocated by <ACE_Allocator: malloc> ).
Virtual void free (void * ptr) = 0;
/// Remove any resources associated with this memory manager.
Virtual int remove (void) = 0;
// = Map manager like functions
/**
* Associate @ a name with @ a pointer. If @ a duplicates = 0 then do
* Not allow duplicate @ a name/@ a pointer associations, else if
* @ A duplicates! = 0 then allow duplicate @ a name/@ a pointer
* Assocations. Returns 0 if successfully binds (1) a previously
* Unbound @ a name or (2) @ a duplicates! = 0, returns 1 if trying
* Bind a previusly bound @ a name and @ a duplicates = 0, else
* Returns-1 if a resource failure occurs.
*/
Virtual int bind (const char * name, void * pointer, int duplicates = 0) = 0;
/**
* Associate @ a name with @ a pointer. Does not allow duplicate
* @ A name/@ a pointer associations. Returns 0 if successfully binds
* (1) a previusly unbound @ a name, 1 if trying to bind a previusly
* Bound @ a name, or returns-1 if a resource failure occurs. When
* This call returns @ a pointer's value will always reference
* Void * that @ a name is associated with. Thus, if the caller needs
* To use @ a pointer (e.g., to free it) a copy must be maintained
* The caller.
*/
Virtual int trybind (const char * name, void * & pointer) = 0;
/// Locate @ a name and pass out parameter via pointer. If found,
/// Return 0, returns-1 if failure occurs.
Virtual int find (const char * name, void * & pointer) = 0;
/// Returns 0 if the name is in the mapping.-1, otherwise.
Virtual int find (const char * name) = 0;
/// Unbind (remove) the name from the map. Don't return the pointer
/// To the caller
Virtual int unbind (const char * name) = 0;
/// Break any association of name. Returns the value of pointer in
/// Case the caller needs to deallocate memory.
Virtual int unbind (const char * name, void * & pointer) = 0;
// = Protection and "sync" (I. e., flushing memory to persistent
// Backing store ).
/**
* Sync @ a len bytes of the memory region to the backing store
* Starting at @ c this-> base_addr _. If @ a len =-1 then sync
* Whole region.
*/
Virtual int sync (ssize_t len =-1, int flags = MS_SYNC) = 0;
/// Sync @ a len bytes of the memory region to the backing store
/// Starting at @ a addr.
Virtual int sync (void * addr, size_type len, int flags = MS_SYNC) = 0;
/**
* Change the protection of the pages of the mapped region to @ a prot
* Starting at <this-> base_addr _> up to @ a len bytes. If @ a len =-1
* Then change protection of all pages in the mapped region.
*/
Virtual int protect (ssize_t len =-1, int prot = PROT_RDWR) = 0;
// Change the protection of the pages of the mapped region to @ a prot
/// Starting at @ a addr up to @ a len bytes.
Virtual int protect (void * addr, size_type len, int prot = PROT_RDWR) = 0;
# If defined (ACE_HAS_MALLOC_STATS)
/// Dump statistics of how malloc is behaving.
Virtual void print_stats (void) const = 0;
# Endif/* ACE_HAS_MALLOC_STATS */
/// Dump the state of the object.
Virtual void dump (void) const = 0;
Private:
// Do not add any state (data members) to this class !!!! See
// <ACE_Allocator: instance> implementation for explanation.
/// Pointer to a process-wide ACE_Allocator instance.
Static ACE_Allocator * allocator _;
// Must delete the <allocator _> if non-0.
Static int delete_allocator _;
};
Recently I have also written several allocator statements, and I have not studied any better implementation methods. But it seems that Mr. Hou's book said that the space configurator should be able to consider reading the hard disk space for allocator space. The virtual memory is probably implemented in this way.
Think about it: a year ago, I used the standard library for the first time and thought that allocator implementation was very advanced. When can I learn it. Later I came to look at Mr. Hou's allocator book and thought I could do the same thing. However, due to my laziness, I haven't practiced it for a long time. Recently I have read the standard library seriously, I have written some profound experiences and can afford my three years of work and study. In fact, there are a lot of things. At the beginning, I felt that they were so advanced and difficult to do. As long as I had the confidence and the method was correct, I would have made a breakthrough once I persisted, that kind of happiness is quite comfortable.
Recently, a programmer who has been using C ++ for nearly five years has a deep understanding of C ++ and open source. I think he has come one step by one. He has a deep understanding of some meta-programming, flexible template usage, advanced use of network programming, server load balancing, Linux kernel mechanism, and underlying windows principles, I still don't know much about what he said. I need to keep up with my own pace and speed up a little.