Mallocator公司

对使用STL有一定经验的程序员的一个常见问题是,“如何编写STL分配器?”。  编写STL分配器并不是特别困难——只有两个成员函数是有趣的:allocate()和deallocate()。  然而,STL分配器必须满足许多其他要求(由C++国际标准第20.1.5节给出,ISO/IEC 1488∶2003),并且这样做的代码大约需要80条编辑线。  从需求中找出代码是非常困难的,但是一旦你看到了代码,就很容易了。

null

一些程序员尝试从std::allocator派生。  我反对这样做;麻烦太多了。  查看std::分配器的实现也很痛苦。

因此,我编写了一个示例STL分配器,它的用途是包装malloc()和free(),我很有想象力地称之为Mallocator。  我仔细地实现了实际生产代码中需要的所有整数溢出检查等。  我已经详尽地评论了Mallocator的哪些部分是样板文件(对于所有、几乎所有或所有无状态分配器都是通用的),以及您必须自定义哪些部分。  希望这能揭开STL分配器实现的神秘面纱:

C:温度>类型mallocator.cpp

//所有分配器都需要以下标头。

#包括  // 大小和ptrdiff和空值都需要

#包括       // 需要放置新的和标准::错误分配

#include//对于std::lengthu错误是必需的

//以下标题包含Mallocator使用的内容。

#包括  // 对于malloc()和free()

#包括  // 对于std::cout

#包括   // 对于std::endl

//以下标题包含main()使用的内容。

#包括      // 对于std::列表

模板类Mallocator{

公众:

//对于几乎所有的分配器,以下内容都是相同的。

typedef T*指针;

typedef const T*常量指针;

typedef T&reference;

typedef const T&constu参考;

typedef T值类型;

typedef sizeu t sizeu type类型;

typedef ptrdiff t difference类型;

T*地址(T&r)常量{

返回&r;

}

常量T*地址(常量T&s)常量{

退货&s;

}

sizeu t maxu size()常量{

//以下内容是为了独立于

//大小的定义,以避免有符号/无符号警告。

返回(静态u cast(0)–静态u cast(1))/sizeof(t);

}

//对于所有分配器,以下条件必须相同。

模板结构重新绑定{

typedef Mallocator其他;

};

布尔接线员=(const Mallocator和其他)const{

回来(*此==其他);

}

空心构造(T*const p,const T&T)const{

void*const pv=静态铸造(p);

新(pv)T(T);

}

无效销毁(T*const p)const;//定义如下。

//当且仅当从*中分配存储时返回true

//可以从其他方取消分配,反之亦然。

//对于无状态分配器,总是返回true。

布尔运算符==(const Mallocator&other)const{

返回true;

}

//默认构造函数、复制构造函数、重新绑定构造函数和析构函数。

//对于无状态分配器为空。

Mallocator(){}

Mallocator(const Mallocator&){}

模板Mallocator(const Mallocator&){}

~Mallocator(){}

//以下内容对于每个分配器都是不同的。

分配(const size)const{

//Mallocator打印诊断信息以演示

//它在做什么。真正的分配器不会这样做。

std::cout<<“分配”<

<<“尺寸”<<尺寸(T)<<“<<标准::endl;

//未指定allocate(0)的返回值。

//Mallocator返回NULL以避免依赖

//关于malloc(0)的实现定义的行为

//(实现可以定义malloc(0)返回NULL,

//在这种情况下,下面的错误分配检查将触发)。

//在这种情况下,所有分配器都可以返回NULL。

如果(n==0){

返回NULL;

}

//所有分配器都应包含整数溢出检查。

//标准化委员会建议std::lengthu error

//在整数溢出的情况下抛出。

如果(n>maxu size()){

throw std::length_error(“Mallocator::allocate()–Integer overflow.”);

}

//Mallocator包装malloc()。

void*const pv=malloc(n*sizeof(T));

//如果内存分配失败,分配器应该抛出std::bad u alloc。

如果(pv==NULL){

throw std::bad_alloc();

}

返回静态u cast(pv);

}

void deallocate(T*const p,const size)常量{

//Mallocator打印诊断信息以演示

//它在做什么。真正的分配器不会这样做。

std::cout<<“取消分配”<

<<“尺寸”<<尺寸(T)<<“<<标准::endl;

//Mallocator包装免费()。

游离(p);

}

//以下内容对于忽略提示的所有分配器都是相同的。

模板T*分配(const sizeU T n,const U*/*const提示*/)常量{

返回分配(n);

}

//分配器不需要是可分配的,所以

//所有分配器都应该有一个未实现的私有

//赋值运算符。请注意,这将触发

//默认情况下关闭(在墙下启用)警告C4626

//“无法生成赋值运算符,因为

//基类赋值运算符在“”中不可访问

//STL头,但是这个警告没有用。

私人:

Mallocator&operator=(常量Mallocator&);

};

//编译器错误使它相信p->~T()没有引用p。

#如果定义u MSCu版本

#pragma警告(推送)

#pragma warning(disable:4100)//未引用的形式参数

#结束

//对于所有分配器,destroy()的定义必须相同。

模板void Mallocator::destroy(T*const p)const{

p->~T();

}

#如果定义u MSCu版本

#pragma警告(pop)

#结束

int main(){

使用名称空间标准;

cout<<“构造l:”<

列表>l;

cout<

l、 推回(1729);

cout<

l、 推吧

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享