一、背景——内存分配的原理
在STL中,Memory Allocator 处于最底层的位置,为一切容器提供存储服务,是一切其他组件的基石。对于一般使用 STL 的用户而言,Allocator 是不可见的,如果需要对 STL 进行扩展,如编写自定义的容器,就需要调用 Allocator 的内存分配函数进行空间配置。这里为什么叫空间配置器而不是内存配置器呢?因为空间不一定是内存,也可能使磁盘或者其他辅助介质。现在,详细的介绍下内存分配原理:
1、内存的分配与对象的构造的顺序
C++中内存分配和对象构造是分开来的,内存的分配类似malloc函数。在内存空间开辟一段空间,但是里面不保存任何数据。对象的构造相当于给这段空间赋值。
2、C++中内存分配一般有三个层次,(注意层次,一层嵌套一层)
- 使用new创建对象, delete删除对象
- 使用allocator分配未初始化的内存,使用construct和destroy构造和析构对象
- 使用operator new分配内存,operator delete删除内存,placement new创建对象,显式调用析构函数析构对象
具体的,有
当使用new表达式时,实际发生三个步骤。首先,该表达式调用名为operator new的标准函数库,分配足够大的原始的未初始化的内存,以保存指定类型的一个对象;接下来,运行该类型的一个构造函数,用指定初始化式构造对象;最后,返回指向新分配并构造的对象的指针。
当使用allocator类时,它提供各种类型的内存分配和对象的构造与撤销,allocator类将内存分配和对象构造分开。当allocator对象分配内存时,它分配适当大小并排列成保存给定类型对象的空间。但是,它分配的内存是未构造的,allocator的用户必须分别使用construct和destory来创建与销毁内存中的对象。
实例
#include<iostream>
#include<memory> //使用allocator必须包含memory
using namespace std;
void main()
{
allocator<int> alloc;
int *ptr=alloc.allocate(1);
alloc.construct(ptr,10);
printf("%d\n",*ptr);
}
当使用标准库函数operator new和operator delete,以及placement new表示式来构造对象。该表达式旨在已分配的原始内存中初始化一个对象,它不分配内存,只构造对象,它可以使用任何构造函数,并直接建立对象。相对于allocator中的construct,这种就比较灵活,因为construct只能使用拷贝构造函数,而在禁止使用拷贝函数的地方,allocator是不能用的。
placement new的形式为:
new (placae-address) type;
new(placae-address) type (initializer-list)
例子1
#include<iostream>
using namespace std;
void main()
{
int *p=static_cast<int*>(operator new[](sizeof(int)));
new (p) int(10);//placement new表示式
printf("%d\n", *p);
}
例子2
#include<iostream>
using namespace std;
class A
{
public:
int data;
};
void main()
{
A *ptr=static_cast<A*>(operator new[](sizeof(A)*2));
new (ptr) A;
printf("%d",(*ptr).data);
}
二、Allocator 的标准接口
Allocator 的作用相当于operator new 和operator delete的功能,只是它考虑得更加细致周全。SGI STL 中考虑到了内存分配失败的异常处理,内置轻量级内存池(主要用于处理小块内存的分配,应对内存碎片问题)实现, 多线程中的内存分配处理(主要是针对内存池的互斥访问)等。
三、自定义的简单的空间配置器
#include<iostream>
using namespace std;
//分配内存
template<typename T>
inline T* _allocate(unsigned int size,T*)
{
T* tmp=static_cast<T*>(operator new[](size*sizeof(T)));
if(tmp==0)
{
cout<<"'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);
}
//析构对象
template<typename T>
inline void _destory(T *ptr)
{
ptr->~T();
}
//我的空间配置器
template<typename T>
class myAllocator
{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef unsigned int size_type;
template<typename U>
struct rebind
{
typedef allocator<U> other;
};
pointer allocate(size_type n,const void *hint=0)
{
return _allocate(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)
{
_destory(p);
}
};
//主函数,检查正确性
void main()
{
myAllocator<int> alloc;
int *ptr=alloc.allocate(2);
alloc.construct(ptr,10);
printf("%d",*ptr);
}
参考:
https://blog.csdn.net/u013011841/article/details/40478571
https://blog.csdn.net/wang13342322203/article/details/99709860