C++空间配置器allocator

一、背景——内存分配的原理

在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

猜你喜欢

转载自blog.csdn.net/sinat_31608641/article/details/107570599