CUJ:标准库:Allocator能做什么?[8]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 taodm 的 blog

使用allocator

    使用allocator的最简单方法,当然是将它们作为参数传给容器类;用

    std::vector<char, malloc_allocator<char> > v;

取代简单的std::vector<char>,或用

      typedef std::list<int, mempool_allocator<int> > list;

      list l(mempool_allocator<int>(p));

取代简单的std::list<int>。

    但是你能做得更多。stl的卖点是它是可扩展性:正如你能写自己的allocator,你也能写你自己的容器类。如果你很小心, 并且你写的容器类使用它的allocator来处理所有的内存相关操作,那么别人将能够加入他们自己的用户自定义allocator。

    诸如std::vector和std::list这样的容器类是很复杂的,而且大部分复杂性与内存管理无关。让我们以一个简单的例子开始,这样我们可以只关注于allocator。考虑一个固定大小数组的类,array,元素的个数是在构造函数中设定的,并且在此之后不会改变。(这有点像std::valarray的一个简化版本。)它有二个模板参数,元素类型和allocator类型。

    容器,和allocator一样,以巢式类型申明开始:value_type, reference,const_reference,size_type,difference_type,iterator,和const_iterator。通常,这些类型中的绝大部分都可以直接从它的allocator中获得--这也解释了为什么容器的value_type必须和allocator中的相匹配。

    当然,iterator类型通常不来自于allocator;通常iterator是一个类,完全取决于容器的内在表示。array类比通常见到的容器简单,因为它实际上将所有元素存储在单块连续内存中;我们只要维护指向内存块开始和结束处的两个指针。iterator就是指针。

    在更进一步之前,我们必须决定:我们将怎样储存allocator?构造函数将接受一个allocator对象作为参数。我们必须在容器的整个生命期内保存它的一个拷贝,因为在析构函数中还需要它。

    依感觉,这儿没什么问题:我们只要申明一个allocator类型的成员变量,然后使用它。方法是正确的,但不爽。毕竟,在99%的时间里,用户都不想考虑有关allocator的事;他们只会写array<int>并使用默认值--而默认的allocator可能是一个没有任何非static成员变量的空类。问题是即使allocator是一个空类,这样的成员变量也会有开销。(这是c++标准所要求的。) 我们的array类将会有三个word的开销,而不是两个。也许一个word的额外开销不是大问题,但总是不爽,它迫使所有用户为一个几乎从不使用的功能承担了开销。

    都很多方法来解决这个问题,其中一些使用了traits类和偏特化。或许最简单的解决方法就是使用(私有)继承而不是成员变量。编译器被允许优化掉空基类,而且时下绝大多数的编译器都这么做了。

    我们最终能写下定义的骨架了:

    template <class t, class allocator = std::allocator<t> >

    class array : private allocator

    {

    public:

      typedef t value_type;

本文关键:CUJ、allocator、STL、Matt Austern
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top