为什么不说allocator是内存配置器而说它是空间配置器?因为空间不一定是内存,空间也可以是磁盘或其他辅助存储介质。你可以写一个allocator直接向硬盘取空间。
set_new_handler:
当operator new申请一个内存失败的时候,会调用set_new_handler设置的函数,参数为0,则抛出异常 。
new运算符和operator new()
operator new():指对new的重载形式,它是一个函数,并不是运算符。对于operator new来说,分为全局重载和类重载,全局重载是void* ::operator new(size_t size),在类中重载形式 void* A::operator new(size_t size)。还要注意的是这里的operator new()完成的操作一般只是分配内存,事实上系统默认的全局::operator new(size_t size)也只是调用malloc分配内存,并且返回一个void*指针。而构造函数的调用(如果需要)是在new运算符中完成的。
int * aptr = new int(10);
delete aptr, aptr = nullptr;
上面的代码是我们最基本也是最常见的使用new和delete的方式,当编译器运行int * aptr = new int(10); 这行代码时,其实是分为两个步骤来执行,第一步,调用operator new(size_t size) 分配内存;第二步在分配的内存上调用placement new(void * ptr) T(); “定位放置 new”,就是把对象构建在指定的ptr指向的内存上,换句话就是在指定的内存上调用构造函数。
#ifndef _JJALLOC_
#define _JJALLOC_
#include<new>//for placement new
#include<cstdlib>//for ptrdiff_t,size_t
#include<climits>//for UINT_MAX
#include<iostream>//for cerr
namespace JJ
{
template<class T>
inline T* _allocate(ptrdiff_t size, T*){
//当operator new申请一个内存失败的时候,会调用set_new_handler设置的函数
//参数为0,则抛出异常
set_new_handler(0);
T* tmp = (T*)(::operator new((size_t)(size*sizeof(T))));
if (tmp == 0){
cerr << "out of memory" << endl;
exit(1);
}
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(value);
//这叫place new,在指针p所指向的内存空间创建一个类型为T1的对象。
//调用的构造函数接受一个类型为const T2&(或其他兼容类型)的参数
}
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;
//rebind allocator of type U
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 T& 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 JJ
#endif _JJALLOC_