STL- space configurator, iterators, traits programming skills

Memory allocation and deallocation

STL has two distributors, a distributor and secondary distributor, the use of secondary distributor, the use of secondary distributor will call a distributor when allocating large memory to perform default, a distributor and use malloc free allocate and free memory. If you assign it two small memory allocator to find from the memory pool to prevent malloc / free overhead.
Two configurator

To understand the principle, not root out the details, achieve only a distributor it is possible:

class first_level_alloc {
public:
    static void* allocate(size_t n) {
        void* result = malloc(n);       //直接使用malloc
        //todo: out of memory handler
        return result;
    }
    static void deallocate(void* p, size_t) {
        free(p);            //直接使用free
    }
};

A distributor, direct calls to malloc and free to allocate and free memory. There is also no case allocation failure treatment.

For ease of use define a wrapper class:

template <typename T, typename Alloc>
class simple_alloc {
public:
    static T* allocate(size_t n) {
        return (0 == n) ? nullptr : static_cast<T *>(Alloc::allocate(n * sizeof(T)));
    }
    static T* allocate() {
        return static_cast<T *>(Alloc::allocate(sizeof(T)));
    }
    static void deallocate(T *p, size_t n) {
        if (0 != n) {
            Alloc::deallocate(p, n * sizeof(T));
        }
    }
    static void deallocate(T *p) {
        Alloc::deallocate(p, sizeof(T));
    }
};

Foreign use this wrapper class template parameter T specifies the type of object you want to assign, Alloc designated distributor because the distributor did not realize two, it is designated as a distributor first_level_alloc.

Object constructors and destructors

Three functions are defined as follows:

template <typename T>
inline void construct(T* p, const T& value) {
    new(p) T(value);   //placement new
}
template <typename T>
inline void destroy(T *p) {
    p->~T();
}
//todo:low efficiency
template <typename ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
    for (; first != last; ++first) {
        destroy(&*first);
    }
}
  1. void construct(T* p, const T& value): P at the position value and returns the copy with the object T configuration. Here used placement new.
  2. void destroy(T *p): Destructor T objects at the point p.
  3. void destroy(ForwardIterator first, ForwardIterator last): Destructor [Object first, last) interval. There is no consideration of efficiency, direct use for the cycle call destroy. STL library using a template specialization, depending on the type iterator points are not trivial destructor, perform different version of specialization. If there is trivial destructor, such as built-in types, then do nothing. If you have a non-trivial destructor is only called that version of the above.

traits to solve the problem

If you want to declare a variable algorithm "within the meaning of the iterator category", how to do?

Case solve the embedded category declared non-pointer iterators

template <typename T>
struct MyIter {                     //模拟迭代器类型
    typedef T value_type;   //内嵌类别声明
    T* ptr;
    MyIter(T* p = 0) :ptr(p) {}
    T& operator*() const {
        return *ptr;
    }
};

template <typename I>
typename I::value_type    //返回类型为迭代器指向的类型
func(I ite) {      //该函数传入一个指针,返回指针指向的值。
    return *ite;
}

int main() {
    MyIter<int> ite(new int(8));
    cout << func(ite);
}

MyIter analog iterator, T is the iterator type referred to by the iterator in the typedef T value_type;rear, able to use MyIter :: value_type define variables of type T.
The above method solves part of the problem, but also an ordinary pointer iterator type, we can not apply the above method to the pointer. For example, the above func, if we pass a pointer, certainly will not compile.

Use template specialization to solve the case of an ordinary pointer

template <typename T>
struct MyIter {
    typedef T value_type;
    T* ptr;
    MyIter(T* p = 0) :ptr(p) {}
    T& operator*() const {
        return *ptr;
    }
};

template <typename I>
struct iterator_traits {            //针对普通迭代器的模板类
    typedef typename I::value_type value_type;
};

template <typename I>
struct iterator_traits<I*> {      //针对指针类型的模板特例化
    typedef I value_type;
};

template <typename I>
typename iterator_traits<I>::value_type
func(I ite) {                   //该函数返回迭代器或这种指向的值
    return *ite;
}

int main() {
    MyIter<int> it(new int(8));
    int* ip = new int(8);
    std::cout << func(ip) << std::endl;
    std::cout << func(it);
}

This defines a template class iterator_traits, the actual use of iterator_traits<I>::value_typethe type referred to is the iterator I, if the iterator is a pointer type, then the match is of itetraor_traits specialization, iterator_traits<I>::value_typecan still obtain the pointer type.

So-called traits is a series of templates and template class specialization. Pointer or related types can be obtained by this iterator class template.

And if an iterator type if desired traits classes with the use and need in the inside thereof defined by typedef value_type type.

Iterator appropriate category

In front of the iterator type referred value_type is one of the relevant categories of iterators, except within the meaning of the iterator type, there are several related iterator type.

  1. value_type: iterator type referred to, on the one already talked about.
  2. difference type: to indicate the distance between two iterators.
  3. reference type: iterator type referred to in reference types.
  4. pointer type: the type referred iterator pointer type.
  5. iterator_category: Category iterator.

Guess you like

Origin www.cnblogs.com/gatsby123/p/11094655.html