顺序容器的定义

顺序容器(sequential container)。它将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素,这就是顺序容器。顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定。

标准库定义了三种顺序容器类型:vector、list 和 deque(是双端队列“double-ended queue”的简写,发音为“deck”)。它们的差别在于访问元素的方式,以及添加或删除元素相关操作的运行代价。标准库还提供了三种容器适配器(adaptors)。实际上,适配器是根据原始的容器类型所提供的操作,通过定义新的操作接口,来适应基础的容器类型。顺序容器适配器包括 stack、queue 和 priority_queue 类型。

顺序容器

 

vector

支持快速随机访问

list

支持快速插入/删除

deque

双端队列

顺序容器适配器

 

stack

后进先出(LIFO)堆栈

queue

先进先出(FIFO)队列

priority_queue

有优先级管理的队列

为了定义一个容器类型的对象,必须先包含相关的头文件,即下列头文件之一:

#include <vector>
#include <list>
#include <deque>

所有的容器都是类模板。要定义某种特殊的容器,必须在容器名后加一对尖括号,尖括号里面提供容器中存放的元素的类型:

vector<string> svec; // empty vector that can hold strings
list<int> ilist; // empty list that can hold ints
deque<Sales_item> items; // empty deque that holds Sales_items

所有容器类型都定义了默认构造函数,用于创建指定类型的空容器对象。默认构造函数不带参数。

为了使程序更清晰、简短,容器类型最常用的构造函数是默认构造函数。在大多数的程序中,使用默认构造函数能达到最佳运行时性能,并且使容器更容易使用。

容器元素的初始化

C<T> c;

创建一个名为 c 的空容器。C 是容器类型名,如 vector,T 是元素类型,如 int 或 string 适用于所有容器。

C c(c2);

创建容器 c2 的副本 c;c 和 c2 必须具有相同的容器类型,并存放相同类型的元素。适用于所有容器。

C c(b,e);

创建 c,其元素是迭代器 b 和 e 标示的范围内元素的副本。适用于所有容器。

C c(n,t);

用 n 个值为 t 的元素创建容器 c,其中值 t 必须是容器类型 C 的元素类型的值,或者是可转换为该类型的值。只适用于顺序容器

C c(n);

创建有 n 个值初始化(第 3.3.1 节)(value-nitialized)元素的容器 c。只适用于顺序容器

将一个容器初始化为另一个容器的副本

当不使用默认构造函数,而是用其他构造函数初始化顺序容器时,必须指出该容器有多少个元素,并提供这些元素的初值。同时指定元素个数和初值的一个方法是将新创建的容器初始化为一个同类型的已存在容器的副本:

vector<int> ivec;
vector<int> ivec2(ivec); // ok: ivec is vector<int>
list<int> ilist(ivec); // error: ivec is not list<int>
vector<double> dvec(ivec); // error: ivec holds int not double

将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须相同。

初始化为一段元素的副本

尽管不能直接将一种容器内的元素复制给另一种容器,但系统允许通过传递一对迭代器间接实现该实现该功能。使用迭代器时,不要求容器类型相同。容器内的元素类型也可以不相同,只要它们相互兼容,能够将要复制的元素转换为所构建的新容器的元素类型,即可实现复制。

迭代器标记了要复制的元素范围,这些元素用于初始化新容器的元素。迭代器标记出要复制的第一个元素和最后一个元素。采用这种初始化形式可复制不能直接复制的容器。更重要的是,可以实现复制其他容器的一个子序列:

// initialize slist with copy of each element of svec
list<string> slist(svec.begin(), svec.end());
// find midpoint in the vector
vector<string>::iterator mid = svec.begin() + svec.size()/2;
// initialize front with first half of svec: The elements up to but
not including *mid
deque<string> front(svec.begin(), mid);
// initialize back with second half of svec: The elements *mid
through end of svec
deque<string> back(mid, svec.end());

指针是迭代器,因此允许通过使用内置数组中的一对指针初始化容器:

char *words[] = {"stately", "plump", "buck", "mulligan"};
// calculate how many elements in words
size_t words_size = sizeof(words)/sizeof(char *);
// use entire array to initialize words2
list<string> words2(words, words + words_size);

分配和初始化指定数目的元素

创建顺序容器时,可显式指定容器大小和一个(可选的)元素初始化式。容器大小可以是常量或非常量表达式, 元素初始化则必须是可用于初始化其元素类型的对象的值:

const list<int>::size_type list_size = 64;
list<string> slist(list_size, "eh?"); // 64 strings, each is eh?

这段代码表示 slist 含有 64 个元素,每个元素都被初始化为“eh?”字符串。

创建容器时,除了指定元素个数,还可选择是否提供元素初始化式。我们也可以只指定容器大小:

list<int> ilist(list_size); // 64 elements, each initialized to 0
// svec has as many elements as the return value from get_word_count
extern unsigned get_word_count(const string &file_name);
vector<string> svec(get_word_count("Chimera"));

不提供元素初始化式时, 标准库将为该容器实现值初始化。采用这种类型的初始化,元素类型必须是内置或复合类型,或者是提供了默认构造函数的类类型。如果元素类型没有默认构造函数,则必须显式指定其元素初始化式。

接受容器大小做形参的构造函数只适用于顺序容器,而关联容器不支持这种初始化。

容器内元素的类型约束

C++ 语言中,大多数类型都可用作容器的元素类型。容器元素类型必须满足以下两个约束:

元素类型必须支持赋值运算。

元素类型的对象必须可以复制。

大多数类型满足上述最低限度的元素类型要求。除了引用类型外,所有内置或复合类型都可用做元素类型。引用不支持一般意义的赋值运算,因此没有元素是引用类型的容器。

除输入输出(IO)标准库类型以及 auto_ptr 类型之外,所有其他标准库类型都是有效的容器元素类型。特别地,容器本身也满足上述要求,因此,可以定义元素本身就是容器类型的容器。IO 库类型不支持复制或赋值。因此,不能创建存放 IO 类型对象的容器。

容器操作的特殊要求

支持复制和赋值功能是容器元素类型的最低要求。此外,一些容器操作对元素类型还有特殊要求。如果元素类型不支持这些特殊要求,则相关的容器操作就不能执行:我们可以定义该类型的容器,但不能使用某些特定的操作。

其中一种需外加类型要求的容器操作是指定容器大小并提供单个初始化式的构造函数。如果容器存储类类型的对象,那么只有当其元素类型提供默认构造函数时,容器才能使用这种构造函数。尽管有一些类没有提供默认构造函数,但大多数类类型都会有。例如,假设类 Foo 没有默认构造函数,但提供了需要一个 int 型形参的构造函数。现在,考虑下面的声明:

vector<Foo> empty; // ok: no need for element default
constructor
vector<Foo> bad(10); // error: no default constructor for Foo
vector<Foo> ok(10, 1); // ok: each element initialized to 1

我们定义一个存放 Foo 类型对象的空容器,但是,只有在同时指定每个元素的初始化式时,才能使用给定容器大小的构造函数来创建同类型的容器对象。

容器的容器

因为容器受容器元素类型的约束, 所以可定义元素是容器类型的容器。例如,

可以定义 vector 类型的容器 lines,其元素为 string 类型的 vector 对象:

// note spacing: use ">>" not ">>" when specifying a container element type
vector< vector<string> > lines; // vector of vectors

注意,在指定容器元素为容器类型时,必须如下使用空格:

vector< vector<string> > lines; // ok: space required between close>
vector< vector<string>> lines; // error: >> treated as shift operator

必须用空格隔开两个相邻的 > 符号,以示这是两个分开的符号,否则,系统会认为 >> 是单个符号,为右移操作符,并导致编译时错误。

posted @ 2018-05-04 11:40  刘-皇叔  阅读(772)  评论(0编辑  收藏  举报