19 September 2016
版权声明:本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名elloop(包含链接)

本系列文章的目录在这里:目录. 通过目录里可以对STL总体有个大概了解

前言

本文展示了如何使用Allocator,例子取自《STL源码剖析》里实现的一个简单的Allocator,从中可以看到Allocator最基本的用法。

STL标准要求1,一个allocator必须有下面这几种类型和成员:

type:
     value_type
     pointer
     const_pointer
     reference
     const_reference
     size_type
     difference_type
memeber:
     rebind
     allocator()
     allocator(const allocator&)
     ~allocator()
     address(reference x)           // return pointer
     address(const_reference x)     // return const_pointer
     allocate(size_type n, const void* = 0)
     deallocate(pointer p, size_type n)
     max_size()
     construct(pointer p, const T& x)
     destroy(pointer p)

下面的allocator<T>实现了这最基本的要求:

#include "inc.h"

#include <new>              // placement new
#include <cstddef>          // ptrdiff_t, size_t
#include <cstdlib>          // exit
#include <climits>          // UINTMAX_MAX

#include <vector>

using namespace std;

NS_BEGIN(elloop);           // namespace elloop {


//
// a simple allocator should at least:
// type:
//      value_type
//      pointer
//      const_pointer
//      reference
//      const_reference
//      size_type
//      difference_type
// memeber:
//      rebind
//      allocator()
//      allocator(const allocator&)
//      ~allocator()
//      address(reference x): return pointer
//      address(const_reference x): return const_pointer
//      allocate()
//      deallocate()
//      max_size()
//      construct()
//      destroy()

template <typename T>
inline T* _allocate(ptrdiff_t size, T*) {
    set_new_handler(0);
    T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
    if (!tmp) {
        cerr << "out of memory" << endl;
        exit(1);
    }
    return tmp;
}

template <typename T>
inline void _deallocate(T* buffer) {
    ::operator delete(buffer);
}

template <typename T1, typename T2>
inline void _construct(T1* p, const T2& value) {
    new(p) T1(value);           // placement new 参考: cpp primer.
}

template <typename T>
inline void _destroy(T* ptr) {
    ptr->~T();
}

template <typename 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 <typename U>
    struct rebind {
        typedef allocator<U> other;
    };

    pointer allocate(size_type n, const void* hint=0) {
        pv("allocate %d for type %s\n", n, typeid(T).name());
        return _allocate((difference_type)n, (pointer)0);
    }

    void deallocate(pointer p, size_type n) {
        pv("deallocate %d for type %s\n", n, typeid(*p).name());
        _deallocate(p);
    }

    void destroy(pointer p) {
        _destroy(p);
    }

    pointer address(reference x) {
        return (pointer)&x;
    }

    const_pointer address(const_reference x) {
        return (const_pointer)&x;
    }

    size_type max_size() const {
        return size_type(UINTMAX_MAX / sizeof(T));
    }
};


RUN_GTEST(AllocatorTest, SimpleAllocator, @@);          // TEST(); google gtest.

vector<int, elloop::allocator<int>> iv{1, 2, 3, 4, 5, 6};
printContainer(iv, "iv = ");  // iv = 1, 2, 3, 4, 5, 6

END_TEST;


NS_END(elloop);

输出:

allocate 6 for type i
iv = 1 2 3 4 5 6
deallocate 6 for type i

可以看到,vector分配空间的时候调用了我自定义的allocator<int>, 打印出了分配的元素类型和个数,个数是6, 类型是:i, 我是使用clang++编译的代码,这里i是int的name。这个name根据编译器的不同而不同,用vc++编译运行int的name就是int而不是本文中的i.


在这里也能看到这篇文章:github博客, CSDN博客, 欢迎访问

  1. 我没有去看最新的标准,这个结论是从《STL源码剖析》里面得出的。 



分享到