C++ 标准库中的allocator是多余的

原创 2009年08月02日 12:13:00

C++ 标准库中的allocator是多余的

我认为C++的allocator是依赖注入的一次失败的尝试。 

C/C++里的内存分配和释放是个重要的事情,我同意,在写library的时候,除了默认使用malloc/free,还应该允许用户指定使用内存分配的函数。用现在的话说,如果library依赖于内存分配与释放,就应该允许用户注入这种依赖。我看到有些C library是支持这个的,可以在初始化时传入两个函数指针,指向内存分配和释放的函数。 

 

问题是,allocator是模板参数,而不是构造函数的参数。这意味着 

 

1. 由于不能从构造函数传入allocator,那么每种类型的allocator必须是全局唯一的(Singleton)。无论SGI 的内存池(称为PoolAlloc),还是简单的new wrapper(称为NewAlloc)都只从一个地方(region)搞到内存,这大大限制了其使用。 (补注:这是 SGI STL 的限制,标准 C++ 运行从构造函数传入 allocator,后面的论述依然成立。)


2. allocator是vector类型的一部分,vector<string, PoolAlloc> 和 vector<string, NewAlloc> 是两个类型,不可相互替换。这不仅暴露了实现,还暴露到了类型上,恐怕没有比这更糟糕的了。 

 

下面举例说明, 

 

对于1,假设我有一个任务(假设是parse),需要分配很多小块内存,总容量不超过20M。为了防止内存泄露及避免内存碎片,我希望在任务开始时,先从系统拿到20M内存,供这个任务使用(parse里分配内存只需要改一个指针,释放内存是空操作),等任务完成后,我一次性释放这20M内存,这样既高效又安全。然而C++的allocator并不能帮我实现这一点,因为它是全局的。我不能替换全局的allocator,因为那会影响其他线程。也不能在运行时指定某个vector<string>用哪种allocator,因为类型是编译时确定的。 

 

对于2,如果我想写一个普通的以vector<string>为参数的函数,这不难 


void process(vector<string>& records); 

 

由于vector<string, PoolAlloc>和vector<string, NewAlloc>类型不同,process只能接受一种。 
但这完全没道理,我不过想访问一个vector<string>,根本不关心它的内存是怎么分配的,却被什么鬼东西allocator挡在了门外。 


我要么提供重载: 
void process(vector<string, NewAlloc>& records); 
void process(vector<string, PoolAlloc>& records); 

要么改写成模板: 
template<typename Alloc> 
void process(vector<string, Alloc>& records);

//(同理可知,如果在一个程序里使用多种allocator,那么所有涉及标准库容器的用户函数都必须改写为函数模板) 

 

无论哪种"解决办法"都会导致代码膨胀,而且给标准库的使用者带来完全不必要的负担。 

 

更糟糕的是,allocator给程序库的作者也带来了不必要的负担。如果想把process(vector<string>& records)放到某个library中,那么为了适应不同的allocator,必须把函数定义放在头文件里(因为这是个函数模板)。明明是针对一个固定类型(vector of string)的函数,却不得不写成函数模板,把实现细节暴露在头文件里,让每个用户都去编译一遍,这真是完全没道理。

 

根据以上的分析,基本上不可能在一个程序里混用多种allocator,既然一个程序只能有一种allocator,那为什么还要放到每个容器的模板参数里呢?提供一个全局的钩子不就行了嘛? 

 

相反,shared_ptr就只有一个模板参数T,而他同样可以指定allocator----在构造时传入。

 

现在看来,vector(以及其他标准库容器)与其增加一个Alloc模板参数,不如在构造时传入两个函数指针,一个allocate,一个deallocate,定制的效果也一样。只不过这么做会让标准委员会的人觉得不够GP,很可能被拍掉。 

 

 

总而言之,allocator并不能达到精确控制(定制)内存分配释放的目的,虽然它名以上是为此而生的。虽然在历史上可能有过正面效果(封装far / near pointer),但现在它无疑就是个累赘。就跟 IOStream 的 Locale/Facet ,auto_ptr 和 valarray 一样,成为C++标准一直要背负的历史包袱。


 

 

标准库 STL :Allocator能做什么?

Allocator是C++语言标准库中最神秘的部分之一。它们很少被显式使用,标准也没有明确出它们应该在什么时候被使用。今天的allocator与最初的STL建议非常不同,在此过程中还存在着另外两个设计...

【C++11新特性】 - 空间配置allocator类

今天我们来讲讲C++的allocator类。allocator类是一个模板,定义在头文件`memory`中,用于内存的分配、释放、管理,它帮助我们将内存分配和对象构造分离开来。具体地说,allocat...

C++中的allocator类(内存分配器)

时间:2014.04.25 地点:基地二楼 —————————————————————————— 一、简述   C++的STL中定义了很多容器,容器的第二个模板参数通常为allocator类型...

C++学习笔记(十) 内存机制与Allocator

C++为我们提供了安全的内存空间申请方式与释放方式,但是new与delete表达式却是把空间的分配回收与对象的构建销毁紧紧的关联在一起。实际上,作为与C语言兼容的语言,C++也为我们提供了更加底层的内...

C++:[STL]浅谈Allocator以及详解STL之sequence container的操作及使用(vector)

// 2016-05-13 补充Allocator(空间配置器)的介绍1.引入STL,即 standard tempalate library,标准模板库,是C++的重要组成部分。C++ STL(标准...
  • linwh8
  • linwh8
  • 2016年05月12日 22:19
  • 5537

c++ Allocator

Allocator是C++语言标准库中最神秘的部分之一。它们很少被显式使用,标准也没有明确出它们应该在什么时候被使用。今天的allocator与最初的STL建议非常不同,在此过程中还存在着另外两个设计...

c++实现一个简单的空间配置器allocator

c++实现一个简单的空间配置器allocator       c++中内存分配和对象构造是分开来的,内存的分配类似malloc函数在内存空间开辟一段空间,但是里面不保存任何数据。对象的构造相...

C++ STL中的自定义Allocator

来源: http://www.cnblogs.com/wpcockroach/archive/2012/05/10/2493564.html> 说一说C++里的allocator。我们知道,C+...

关于 std::set/std::map 的几个为什么

陈硕 (chenshuo.com)2013-01-20std::set/std::map (以下用 std::map 代表) 是常用的关联式容器,也是 ADT(抽象数据类型)。也就是说,其接口(不是 ...
  • Solstice
  • Solstice
  • 2013年01月20日 13:22
  • 50027

C++ 工程实践(4):二进制兼容性

陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice 本文主要讨论 Linux x86/x86-64 平台,偶尔会举 Windows 作为反面教材。 C...
  • Solstice
  • Solstice
  • 2011年03月09日 10:46
  • 22029
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ 标准库中的allocator是多余的
举报原因:
原因补充:

(最多只允许输入30个字)