C++/C学习笔记(十)
——存储分配器和适配器
1.存储分配器
STL容器元素的存储空间是动态分配和释放的,不同的硬件平台和操作系统对内存的管理方法和使用方法各不相同,STL为容器类定义了一个专门负责存储管理的类——allocator,但它仅针对内存管理。
Allocator类是一个模版,作为容器类模版的一个policy参数,它不仅与将要为之分配空间的数据对象的类型无关,并且为动态内存的分配和释放提供了面向对象的接口。它是对new运算符的更高层次的抽象,即隐藏了底层的内存模式(段内存、共享内存、分布式内存等),封装了动态内存分配和释放操作,隐藏了指针本身的大小、存储空间重分配模型及内存页大小等细节,提供了更好的可移植性。因此,allocator类为string类、容器类及用户自定义类型、应用程序框架和类库等提供了独立于硬件和操作系统的接口。
2.适配器
(1)容器适配器
基本的容器只有几种,而可用的数学模型却又很多,我们可以在基本容器的基础上通过改变它们的接口来实现特殊的容器,这就是容器适配器(Container Adapter),有时俗称二次封装。
适配器(Adapter)往往是利用一种已有的比较通用的数据结构来实现更加具体的,更加贴近实际应用的数据结构。因此容器适配器窄化了(narrow)或者说强化了基础容器的接口,而基础容器的接口是比较通用的。例如stack就是比较特殊的容器,它可使用deque或list等来实现,但是去掉了那些不符合stack特点的操作,stack的接口受到了比deque和list的接口更强的约束。此外,stack使用deque或list的back()、push_back()、pop_back()操作分别实现其top()、push()、和pop()操作。如下例:
/*****************************************************/
template<typename T,typename S=deque<T>>
class stack{
...
T&top(){return (c.back());}
const T&top() const{return (c.back());}
void push(const value_type&v){c.push_back(v);}
void pop(){c.pop_back();}
...
private:
S c;
};
/*****************************************************/
(2)迭代器适配器(Iterator Adapter)
插入式迭代器(Insert Iterator)以一个容器为操作对象,并向其中插入元素来完成批量输入/输出功能,包括back_insert_iterator、front_insert_iterator和insert_iterator。对于一个back_insert_iterator执行赋值操作就相当于对其绑定的容器执行push_back()操作,对一个front_insert_iterator执行赋值操作就相当于对其绑定的容器执行push_front()操作,而对一个insert_iterator执行赋值操作就相当于对其绑定的容器执行insert()操作。同时对于输出迭代器,反引用(*)、前进(++)、后退(--)、取元素地址(->)等操作都是无意义的,但是为了与普通迭代器具有一致的行为模式,还是保留了反引用和前进的能力,并关闭它们的功能,仅简单地返回自己。
输出流迭代器(ostream_iterator)则通过绑定一个ostream对象来完成批量输出功能,即内部维护一个ostream对象,并将赋值操作(operator=)转换为对该ostream对象的运算符operator<<的调用。同样它关闭了反引用和前进功能,并且禁止后退和取地址操作。无论是把容器的内容全部输出到磁盘文件还是终端,都可以使用该迭代器。如下例:
/*****************************************************/
#include<list>
#include<algorithm>
#include<iterator>
#include<iostream>
using namespace std;
void mian()
{
list<int> li;
for(int k=0;k<10;k++){
li.push_back(k);
}
copy(li.begin,li.end(),ostream_iterator<int>(cout,""));
}
/*****************************************************/
类似地,输入流迭代器(istream_iterator)绑定了一个istream对象来完成批量输入功能,并将前进操作(++)转换为对istream对象的运算符operator<<的调用。该迭代器既可以用于终端输入也可以用于磁盘文件输入。用法如下:
/*****************************************************/
#include<list>
#include<algorithm>
#include<iterator>
#include<iostream>
using namespace std;
void mian()
{
list<int> li;
istream_iterator<int> eos,isiter(cin);
copy(isiter,eos,back_inserter(li));
copy(li.begin,li.end(),ostream_iterator<int>(cout,""));
}
/*****************************************************/
反向迭代器(Reverse Iterator)用于将一个指定的迭代器的迭代行为反转(前进变后退,后退变前进),可用于修饰除前进迭代器外的其他类型迭代器。容器具有的rbegin()和rend()方法返回的就是这种类型的迭代器。