Comparison of Three Types of Allocator source code

Source: Internet
Author: User

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.

// TEMPLATE CLASS allocatortemplate<class _Ty>class allocator: public _Allocator_base<_Ty>{// generic allocator for objects of class _Typublic:typedef _Allocator_base<_Ty> _Mybase;typedef typename _Mybase::value_type 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 _Valreturn (&_Val);}const_pointer address(const_reference _Val) const{// return address of nonmutable _Valreturn (&_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 elementsreturn (_Allocate(_Count, (pointer)0));}pointer allocate(size_type _Count, const void _FARQ *){// allocate array of _Count elements, ignore hintreturn (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.

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 ).

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 to   * bind a previously 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 previously unbound @a name, 1 if trying to bind a previously   * bound @a name, or returns -1 if a resource failure occurs.  When   * this call returns @a pointer's value will always reference the   * 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 by   * 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 the   * 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 the  // <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.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.