一、 自定义allocator
1.1 需要实现的类型
template <class T>
class my_allocator
{
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template <class U>
struct rebind { typedef allocator<U> other; };
// remaining member functions described below
// ...
};
有的容器可能需要构造多种类型的allocator,比如hashmap
的bucket,这时候就需要rebind:
typedef A::rebind<Node>::other Node_Allocator;
1.2 相关函数
-
pointer address(reference r) const
Returns the address of r as a pointer type. This function and the following function are used to convert references to pointers. -
const_pointer address(const_reference r) const
Returns the address of r as a const_pointer type. -
pointer allocate(size_type n, allocator<U>::const_pointer hint=0)
Allocates storage for n values of T. Uses the value of hint to optimize storage placement, if possible. -
void deallocate(pointer)
Deallocates storage obtained by a call to allocate. -
size_type max_size()
Returns the largest possible storage available through a call to allocate. -
void construct(pointer p, const_reference val)
Constructs an object of type T at the location of p, using the value of val in the call to the constructor for T. -
void destroy(pointer p)
Calls the destructor on the value pointed to by p.
1.3 实现
#include <stdio.h>
#include <new>
#include <cstddef>
#include <cstdlib>
#include <cstdlib>
#include <climits>
#include <vector>
#include <iostream>
using namespace std;
namespace jack{
template <typename T>
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>
void _deallocate(T* buffer){
::operator delete(buffer);
}
template <typename T1, typename T2>
void _construct(T1 *p, const T2& value) {
// placement new
new(p) T1(value);
}
template <typename T>
inline void _destroy(T* ptr){
ptr->~T();
}
template <typename T>
class allocator {
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = size_t;
using difference_type = ptrdiff_t;
template <typename U>
struct rebind {
typedef allocator<U> other;
};
pointer allocate(size_type n, const void* hint=0) {
printf("allocate %zu for type %s\n", n, typeid(T).name());
return _allocate((difference_type)n, (pointer)0);
}
void deallocate(pointer p, size_type n) {
printf("deallocate %zu 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));
}
};
};
int main (int argc, char *argv[])
{
vector<int, jack::allocator<int>> iv{1, 2, 3, 4, 5};
return 0;
}