Six major STL components-Allocator (memory allocation, profound things) and six stl

Source: Internet
Author: User
Tags types of functions

Six major STL components-Allocator (memory allocation, profound things) and six stl

SGI has designed a dual-layer configurator. The first-level configurator directly uses malloc () and free (). The second-level configurator uses different policies as needed: when the configuration block exceeds bytes, the first-level provisioner is called as "large enough". When the configuration area is smaller than bytes, it is regarded as "too small". In order to reduce the extra burden, instead of using the first-level configurator. The whole design only opens the first-level configurator, depending on whether _ USE_MALLOC is defined:

1 # ifdef _ USE_MALLOC 2... 3 typedef _ malloc_alloc_template <0> malloc_alloc; 4 typedef malloc_alloc alloc; // set alloc to level 1 configurator 5 # else 6 // set alloc to Level 2 configurator 7 typedef _ default_alloc_template <__node_allocator_threads, 0> alloc; 8 # endif /*! _ USE_MALLOC */

SGI STLLevel 1 Configurator

Template <int inst>

Class _ malloc_alloc_template {...} ;

Note:

1. allocate () directly uses malloc (), and deallocate () directly uses free ().

2. Simulate C ++'s set_new_handler () to handle insufficient memory. The first-level configurator uses the C functions such as malloc (), free (), and realloc () to execute the actual memory configuration, release, and reconfiguration operations.

SGI STLLevel 2 Configurator

Template <bool threads, int inst>

Class _ default_alloc_template {...} ;

Note:

1. Maintain 16 free lists and configure 16 small blocks. The memory pool is configured with malloc. If the memory is insufficient, call the first-level configurator.

2. If the required block is greater than 128 bytes, call the first-level configurator.

1 template <class _ T1, class _ T2> 2 inline void _ Construct (_ T1 * _ p, const _ T2 & _ value) {3 new (void *) _ p) _ T1 (_ value); 4} 5 6 template <class _ T1> 7 inline void _ Construct (_ T1 * _ p) {8 new (void *) _ p) _ T1 (); 9}

The above two functions are used to construct an object of Type T1 and are returned by the pointer p as the parameter.

Where the placement new operator is used in new (_ p) _ T1 (_ value, it is used to create a _ T1 object at the memory address _ p through the copy method. (Placement new can be used to construct an object with the specified type of constructor at the specified memory address ).

In terms of object destruction, stl_construct.h also provides two types of analysis methods:

1 template <class _Tp>2 inline void _Destroy(_Tp* __pointer) {3   __pointer->~_Tp();4 }5 6 template <class _ForwardIterator>7 inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {8   __destroy(__first, __last, __VALUE_TYPE(__first));9 }

In the first version, the Destructor accepts a pointer to parse the object indicated by the pointer. In the second version, the Destructor accepts the first and last iterators, analyze the objects within the range of the two iterators.

In the destroy function of the second version, the traits Technique Used in STL is used to obtain some features of the current object, then, call corresponding methods for objects with different features based on different features. In destroy in stl_construct.h, STL analyzes the has_trivial_destructor feature type of the object referred to by the iterator (only two types are available: true_type and false_type). If it is true_type, STL will do nothing; if it is false_type, The destructor of each object is called to destroy this set of objects.

In addition, stl_construct provides a special version of the destroy function for some basic types of objects. These basic types are char, int, float, double, and long. When destroy parameters are of these basic types, destroy does not do anything.

Memory space management tool alloc

I want to introduce STL allocator in a bottom-down order. First, let's talk about the two built-in splitters in STL, then introduce how STL encapsulates these two splitters to provide a unified interface for external use, and finally use a vector example to see how containers use this allocator.

1 _ malloc_alloc_templateMemory distributor

The allocator is an encapsulation of malloc, realloc, and free:

 1 static void* allocate(size_t __n) 2   { 3     void* __result = malloc(__n); 4     if (0 == __result) __result = _S_oom_malloc(__n); 5     return __result; 6   } 7  8   static void deallocate(void* __p, size_t /* __n */) 9   {10     free(__p);11   }12 13   static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz)14   {15     void* __result = realloc(__p, __new_sz);16     if (0 == __result) __result = _S_oom_realloc(__p, __new_sz);17     return __result;18   }

When malloc and realloc are called to request memory space, oom_malloc () and oom_realloc () are called. These two functions call the out of memory handler processing function that the user passes over and over again, until memory can be applied through malloc or realloc. If the user does not pass _ malloc_alloc_oom_handler, __malloc_alloc_template, the _ THROW_BAD_ALLOC exception will be thrown. Therefore, tasks with insufficient memory are handed over to class customers.

2 _ default_alloc_templateDistributor

This distributor uses the memory pool idea to effectively avoid the problem of internal fragments (by the way, we will introduce the internal and external fragments: internal fragments are the memory space that has been allocated but cannot be used. External fragments are idle blocks that cannot be allocated due to the small size ). If the applied memory block is greater than 128 bytes, the requested operation will be handed over to the _ malloc_alloc_template distributor for processing. If the applied block size is less than bytes, the memory is allocated from the memory pool maintained by this distributor. The splitter maintains the idle space in the memory pool using the idle linked list. The idle linked list is similar to the following shape:

1 template <class _ Tp, class _ Alloc> 2 class simple_alloc {3 4 public: 5 static _ Tp * allocate (size_t _ n) 6 {return 0 = _ n? 0: (_ Tp *) _ Alloc: allocate (_ n * sizeof (_ Tp);} 7 static _ Tp * allocate (void) 8 {return (_ Tp *) _ Alloc: allocate (sizeof (_ Tp);} 9 static void deallocate (_ Tp * _ p, size_t _ n) 10 {if (0! = _ N) _ Alloc: deallocate (_ p, _ n * sizeof (_ Tp);} 11 static void deallocate (_ Tp * _ p) 12 {_ Alloc: deallocate (_ p, sizeof (_ Tp) ;}13 };

When the user calls the distributor, the alloc to be used is passed for the second template parameter of simple_alloc.

Vector (User-mode) uses the STL distributor code. We can see that the basic class of vector calls simple_alloc as its distributor:

1 template <class _ Tp, class _ Alloc> 2 // cobbliu Note: STL vector's base class 3 class _ Vector_base {4 public: 5 typedef _ Alloc allocator_type; 6 allocator_type get_allocator () const {return allocator_type ();} 7 8 _ Vector_base (const _ Alloc &) 9: _ M_start (0), _ M_finish (0 ), _ M_end_of_storage (0) {} 10 _ Vector_base (size_t _ n, const _ Alloc &) 11: _ M_start (0), _ M_finish (0), _ M_end_of_storage (0) 12 {13 _ M_start = _ M _ Allocate (_ n); 14 _ M_finish = _ M_start; 15 _ M_end_of_storage = _ M_start + _ n; 16} 17 18 ~ _ Vector_base () {_ M_deallocate (_ M_start, _ M_end_of_storage-_ M_start);} 19 20 protected: 21 _ Tp * _ M_start; 22 _ Tp * _ M_finish; 23 _ Tp * _ M_end_of_storage; 24 25 typedef simple_alloc <_ Tp, _ Alloc> _ M_data_allocator; 26 _ Tp * _ M_allocate (size_t _ n) 27 {return _ M_data_allocator :: allocate (_ n);} 28 void _ M_deallocate (_ Tp * _ p, size_t _ n) 29 {_ M_data_allocator: deallocate (_ p, _ n) ;}30 };

Basic memory processing tools

In addition to the memory distributor, STL provides three types of memory processing tools: uninitialized_copy (), uninitialized_fill (), and uninitialized_fill_n (). The implementation code of these three types of functions is in the header file stl_uninitialized.h.

Uninitialized_copy () is as follows:

1 template <class _InputIter, class _ForwardIter>2 inline _ForwardIter3   uninitialized_copy(_InputIter __first, _InputIter __last,4                      _ForwardIter __result)5 {6   return __uninitialized_copy(__first, __last, __result,7                               __VALUE_TYPE(__result));8 }

Uninitialized_copy () will copy the object between iterator _ first and _ last to the place where iterator _ result starts. It calls _ uninitialized_copy (_ first, _ last, _ result ,__ VALUE_TYPE (_ result )) determines whether the object referred to by the iterator _ result is of the POD type (the POD type refers to the class with the constructor, deconstructor, copy, and assignment functions). If it is of the POD type, the copy Implementation of the algorithm library is called; otherwise, the iterator _ first ~ is traversed ~ Elements between _ last and create new elements one by one at the start address of _ result.

Uninitialized_fill () is as follows:

1 template <class _ForwardIter, class _Tp>2 inline void uninitialized_fill(_ForwardIter __first,3                                _ForwardIter __last, 4                                const _Tp& __x)5 {6   __uninitialized_fill(__first, __last, __x, __VALUE_TYPE(__first));7 }

Uninitialized_fill () initializes all elements in the range of _ first and _ last in the iterator to x. It calls _ uninitialized_fill (_ first, _ last, _ x, _ VALUE_TYPE (_ first )) it will determine whether the object referred to by iterator _ first is of the POD type. If it is of the POD type, it will call the fill implementation of the Algorithm Library; otherwise, it will be constructed one by one.

Uninitialized_fill_n () is like the following:

1 template <class _ForwardIter, class _Size, class _Tp>2 inline _ForwardIter 3 uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x)4 {5    return __uninitialized_fill_n(__first, __n, __x, __VALUE_TYPE(__first));6 }

Uninitialized_fill_n () initializes n elements at the beginning of iterator _ first to x. It calls _ uninitialized_fill_n (_ first, _ n, _ x, _ VALUE_TYPE (_ first) to determine whether the object indicated by iterator _ first is of the POD type, if yes, the fill_n Implementation of the algorithm library is called; otherwise, the algorithm is constructed one by one.

 

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.