9.2.3 begin和and成员

begin和and操作生成指向容器第一个元素和尾元素之后位置的迭代器。

list<string> a = {"Milton", "Shakespeare", "Austen"};
auto it1 = a.begin();
auto it2 = a.rbegin();
auto it3 = a.cbegin();
auto it4 = a.crbegin();

不以c开头的函数都是被重载过的。当对一个非常量对象调用这些成员时,得到的是返回iterator的类型。只有在对一个const对象调用这些函数时,才会得到一个const版本。与const指针和引用类似,可以将一个普通的iterator转换为对应的const_iterator,但反正不行。

list<string>::iterator it5 = a.begin();
list<string>::const_iterator it6 = a.begin();
auto it7 = a.begin(); //仅当a是const时,it7是const_iterator
auto it8 = a.cbegin();

当不需要写访问时,应使用cbegin和cend。

9.2.4 容器定义和初始化

每个容器都定义了一个默认构造函数。出array之外,其他容器的默认构造函数都会创造一个指定类型的空容器,且都可以接受指定容器大小和元素初始值的参数。

------------------- 容器定义和初始化
C c 默认构造函数,如果C是一个array,则c中元素按默认方式初始化,否则c为空
C c1(c2) c1初始化为c2的拷贝。c1、c2必须是相同类型,对于array类型,两者还必须有相同大小
C c1 = c2 同上
C c{a,b,c...} c初始化为初始化列表中元素的拷贝。列表中元素类型必须与c相同。对于array类型,列表中元素数目必须等于或小于array的大小。
C c = {a,b,c...} 同上
- 只有顺序容器(除了array)才能接受大小参数
C seq(n) seq包含n个元素,这些元素进行了值初始化,此构造函数是explicit的,string不适用。
C seq(n,t) seq包含n个初始量为t的值
  • 将容器初始化为另一个容器的拷贝 为了创建一个容器为另一个容器的拷贝,两容器的类型及其元素必须匹配。不过,当传递迭代器参数来拷贝一个范围时,就不要求容器类型是相同的了。而且,新容器和原容器的元素类型也可以不同,只要将拷贝的元素转换为要初始化的容器的类型即可。
list<string> authors = {"Milton", "Shakespeare", "Austrn"};
vector<const char*> articles = {"a", "an", "the"};
list<string> list2(authors);
deque<string> authList(authors); //错误
vector<string> words(articles); //错误
forward_list<string> words2(articles.begin(), articles.end()); //正确
  • 列表初始化

  • 与顺序容器大小相关的构造函数

  • 标准库array具有固定大小

与内置数组一样,标准库array的大小也是类型的一部分。当定义一个array时,除了指定元素类型,还要指定容器大小。

array<int,42> //类型为:保存42个int的数组
array<string,10>
array<int,42>::size_type i;

由于大小是array的一部分,array不支持普通容器的构造函数。一个默认构造array是非空的,它包含了与其大小一样多的元素,这些元素都被默认初始化,就像一个内置数组。如果元素类型是类类型,呢么该类必须有一个默认构造函数,以便值初始化正常进行。

array<int, 10> ital1; //10个默认初始化的int
array<int ,10> ital2 = {0,1,2,3,4};
array<int, 10> ital3 = {42}; //第一个元素为42,其余为0

可以对array进行拷贝或者对象赋值的操作

array digs[10] = {0,1,2,3,4};
int copy[10] = digs; //错误,内置数组不支持拷贝或赋值
array<int, 10> digits = {0,1,2,3,4};
array<int, 10> copy = digits; //正确