Space Configurator
From the implementation of the STL, the first thing to understand is the space Configurator, because the entire STL operation objects are placed in the container, and the container needs a certain allocation of space to place data. standard interface for Space Configurator
Standard interface, some typedef allocator::value_type;
Allocator::p ointer;
Allocator::const_pointer;
Allocator::reference;
Allocator::const_reference;
Allocator::size_type;
Allocator::d Ifference_type;
Allocator::rebind//A nested class Template,class rebind<u> has a unique member other, that is a TypeDef, represents allocator<u> Allocator::allocator ()//default constructor Allocator::allocator (const allocator&)//copy constructor template & Lt;class u>allocator::allocator<const allocator<u>&)//Generic copy constructor allocator::~ Allocator ()//default constructor pointer allocator::address (reference x) const//Return object address, equivalent to &x Const_pointer al
Locator::address (const_reference x) const//Return the address of the object, equivalent to &x pointer allocator::allocate (size_type n, const void* = 0) The configuration space is sufficient to store N T objects, and the second parameter is a hint that may be exploited to enhance the culture or completely ignore the void allocator::d eallocate (Pinter P, size_type N)//space previously configured Size_ Type allocator::max_size () const//By returning the maximum space void allocator::constructor that can be successfully configured (pointer p, const T&X)//equivalent to new (const void* p) T (x) placement new void Allocator::d Estroy (Pinter P)//equivalent to P->~t ()
design A simple space configurator
#ifndef _test_alloc_ #define _TEST_ALLOC_ #include <new>//For placement new #include <cstddef>//For Ptrdi ff_t, size_t #include <cstdlib>/For exit () #include <climits>//For Unit_max #include <iostream>// For Cerr namespace Test_alloc {Template <class t> inline t*-_allocate (ptrdiff_t size, t*) {std::s
Et_new_handler (0);
t* tmp = (t*) (:: Operator new ((size_t) (Size * sizeof (T)));
if (TMP = = 0) {Std::cerr << "out of Memory" << Std::endl;
return TMP;
} template <class t> inline void _deallocate (t* buffer) {:: operator delete (buffer); Template <class T1, class t2> inline void _construct (t1* p, const t2& value) {new (P) T1 (val
UE);
} template <class t> inline void _destroy (t* ptr) {ptr->~t (); } template <class t> class Allocator {public:typedEF T value_type;
typedef t* Pointer;
typedef const T* Const_pointer;
typedef t& Reference;
typedef const t& Const_reference;
typedef size_t SIZE_TYPE;
typedef ptrdiff_t DIFFERENCE_TYPE;
Template <class u> struct rebind {typedef allocator<u> other;
Pointer allocate (size_type N, const void* hint = 0) {return _allocate ((Difference_type) n, (pointer) 0);
} void Deallocate (pointer p, Size_type N) {_deallocate (P);
} void construct (pointer p, const value_type& value) {_construct (P, value);
} void Destroy (pointer p) {_destroy (P);}
Pointer address (reference x) {return (pointer) &x;
} const_pointer const_address (Const_reference x) {return (Const_pointer) &x; } size_type max_size () const {return size_type (uint_max/sizeof (T));
}
};
//End of namespace #endif #include <vector> int main () {int temp[5]{1, 2, 3, 4, 5};
Std::vector<int, test_alloc::allocator<int>> IV (temp, temp+5);
for (int i = 0; i < 5; ++i) {std::cout << iv[i] << Std::endl;
return 0; }
(It is worth noting that the-STD=C++11 command must be added to the terminal to use c++11)
The SGI STL uses a proprietary, suboptimal, and efficient special configuration that will be mentioned later. In fact, the SGI STL still provides a standard Configurator interface, with the configuration of the standard interface named Simple_alloc. SGI Space Configurator with secondary collocation force
SGI STL configuration is different from the standard specification, its name is alloc rather than allocator, and does not accept any parameters.
Vector<int, Std::alloc> IV;
In STL, each container specifies its default space configurator. 1. SGI Special Space Configurator, Std::alloc
In general, C + + memory configuration operations and release operations are called New,delete.
Class foo{...};
foo* pf = new Foo;
Delete PF;
New actually contains two operations 1) called:: operator new config Memory 2 calls Foo::foo () to construct object contents.
Delete also contains two stages: 1 calls destructor 2) frees memory
The STL allocator separates the two phases, and the memory configuration operation and release is responsible for the allocate () and deallocate (), and the object constructs and destructors are construct () and destroy ().
2. Construction and destructor tools: Construct () and destroy ()
The following gives the < STL _ Construct.h > part of the content.
#include <new>//placement new template <class T1, class t2> inline void construct (t1* p, const t2^ value) {
New (p) T1 (value); } template <class t> inline void Destroy (t* pointer) {pointer->~t ();}//Destroy band range version template <clas s forwarditerator> inline void Destroy (ForwardIterator-I, ForwardIterator last) {__destroy (i, Last, Value_
Type (a); }//Interpretation element numeric type has trivial destructor template <class ForwardIterator, class t> inline void __destroy (forwarditerator ForwardIterator last, t*) {typedef typename __type_traits<t>::has_trivial_destructor Trivial_destructor
;
__destroy_aux (The Last, Trivial_destructor ()); //If there are trivial destructor template <class ForwardIterator, class t> inline void __destroy_aux (ForwardIterator fir
St, ForwardIterator, __flase_type) {for (; i < last; ++first) {Destroy (&*first); }//If there is trivial destructor, then nothing is done template <class FOrwarditerator, class t> inline void __destroy_aux (ForwardIterator-I, ForwardIterator last, __true_type) {}//Positive Special version of char* and wchar_t* inline void Destroy (char*, char*) {} inline void Destroy (wchar_t*, wchar_t*) {}
It is noteworthy that the above constructor () accepts a pointer p and an initial value, which is used to set the initial value to the space indicated by the pointer, which is the function of the placement new operator.
Destroy, however, accepts pointers and invokes their destructors. The accepted version requires special attention, and when the scope is very large, the constant invocation of the destructor may result in a very low efficiency, so at this point we need to determine whether the destructor has to be invoked, (__type_traits), to distinguish between two different situations. As to how to judge whether the destructor is trivial, it will be explained in future articles. 3. Configuration and release of space Std::alloc
This explains the structure and destructor of the object after the memory configuration, and now we discuss the configuration and release of memory.
The space configuration before the object is constructed and the space release after the object is reconstructed by < stl_alloc.h > is responsible for the design philosophy of SGI to the system heap requirements space. Consider multithreading status. Contingency measures when memory is low. Consider the potential memory fragmentation problems caused by too much "small chunks".
(multithreading processing is excluded here)
Considering the possible memory fragmentation problems with small chunks, SGI designed a two-tier Configurator, with the first-quarter configurator directly calling malloc () and free () (that is, operator new and operator delete). The second-level Configurator uses a different policy depending on the situation: when the configuration block is larger than 128bytes and is considered "large enough," the first level Configurator is invoked. When the configuration block is less than 128bytes, it is considered "too small" and, in order to reduce the additional burden, a complex memory pool collation is used without recourse to the first level configurator. Whether the entire design is open to a second-level configurator depends on whether the __use_malloc is defined.
#ifdet __use_malloc ...
typedef __malloc_alloc_template<0> MALLOC_ALLOC;
typedef Malloc_alloc ALLOC; make Alloc the first level configurator
#else
...
typedef __default_alloc_template<__node_allocator_threads, 0> alloc;// alloc for second-level configurator
#endif
It is particularly noted that Alloc does not accept any template type parameters.
Whether Alloc is defined as a first-level or second-level configurator, SGI also wraps an interface for it as follows, enabling the Configurator interface to conform to the STL specification:
Template<class T, class alloc>
class Simple_alloc {public
:
static t* Allocate (size_t N) {
return 0 = = n? 0: (t*) alloc::aloocate (n * sizeof (T));
}
Static t* Allocate (void) {return
(t*) alloc::allocate (sizeof (T));
static void Deallocate (t *p, size_t N) {
if (0!= N) {
Alloc::d eallocate (P, n * sizeof (t));
}
static void deallocate (T *p) {
Alloc::d eallocate (P, sizeof (t));
}
;
In fact, the four member functions within it are simply a call to the member function passed to the Configurator, which causes the configuration unit of the configurator to change from bytes to the size of the individual element.
This interface is used by SGI STL containers.
Template <class T, class Alloc = alloc>
class Vector {
protected:
typedef simple_alloc<value_type, Alloc> Data_allocator;
void Deallocate () {
if (...) {
data_allocator::d eallocate (Start, End_of_storage-start);
}
}
...
};
The relationship of the secondary Configurator,
Interface packaging, and the actual use of the way, see the following figure: