现在的位置: 首页 > 综合 > 正文

chapter9顺序容器

2014年11月03日 ⁄ 综合 ⁄ 共 3855字 ⁄ 字号 评论关闭

为了使程序更清晰、简短,容器类型最常用的构造函数是默认构造函数。在大多数的程序中,使用默认构造函数能达到最佳运行时性能,
并且使容器更容易使用。
将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须相同。

C++ 语言中,大多数类型都可用作容器的元素类型。容器元素类型必须满足以下两个约束:
元素类型必须支持赋值运算。
元素类型的对象必须可以复制。

除了引用类型外,所有内置或复合类型都可用做元素类型。引用不支持一般意义的赋值运算,因此没有元素是引用类型的容器。
除输入输出(IO)标准库类型(以及第 17.1.9 节介绍的 auto_ptr 类型)之外,所有其他标准库类型都是有效的容器元素类型。

注意,在指定容器元素为容器类型时,必须如下使用空格:
     vector< vector<string> > lines; // ok: space required between close >
     vector< vector<string>> lines; // error: >> treated as shift operator
必须用空格隔开两个相邻的 > 符号,以示这是两个分开的符号,否则,系统会认为 >> 是单个符号,为右移操作符,并导致编译时错误。

常用的迭代器运算:
*item    item->mem     item++/--   ==      !=

==================================仅有vector和deque支持的运算:================================================
>  <  >=   <=     item+n       item-n    +=     -=

C++ 语言使用一对迭代器标记迭代器范围(iterator range),这两个迭代器分别指向同一个容器中的两个元素或超出末端的下一位置,
通常将它们命名为 first 和 last,或 beg 和 end,用于标记容器中的一段元素范围。

此类元素范围称为左闭合区间(left-inclusive interval),其标准表示方式为:

     // to be read as: includes first and each element up to but not including last
     [ first, last )

表示范围从 first 开始,到 last 结束,但不包括 last。迭代器 last 可以等于 first,或者指向 first 标记的元素后面的某个元素,
但绝对不能指向 first 标记的元素前面的元素。

修改容器的内在状态或移动容器内的元素。这样的操作使所有指向被移动的元素的迭代器失效,也可能同时使其他迭代器失效。使用
无效迭代器是没有定义的,可能会导致与悬垂指针相同的问题。
任何 insert 或 push 操作都可能导致迭代器失效。当编写循环将元素插入到 vector 或 deque 容器中时,程序必须确保迭代器在
每次循环后都得到更新。
不要存储 end 操作返回的迭代器。添加或删除 deque 或 vector 容器内的元素都会导致存储的迭代器失效。

 reverse_iterator          按逆序寻址元素的迭代器  对应的还有rbegin();rend();成员函数
 const_reverse_iterator       元素的只读(不能写)逆序迭代器
 difference_type    足够存储两个迭代器差值的有符号整型,可为负数
 简单地说,逆序迭代器从后向前遍历容器,并反转了某些相关的迭代器操作:例如,在逆序迭代器上做 ++ 运算将指向容器中的
 前一个元素。
 
 泛型编程的时候使用比较多:
 value_type       元素类型
 reference         元素的左值类型,是 value_type& 的同义词
 const_reference  元素的常量左值类型,等效于 const value_type&
 
 
在容器中添加元素时,系统是将元素值复制到容器里。类似地,使用一段元素初始化新容器时,新容器存放的是原始元素的副本。
被复制的原始值与新容器中的元素各不相关,此后,容器内元素值发生变化时,被复制的原值不会受到影响,反之亦然。

使用下标运算的另一个可选方案是 at 成员函数。这个函数的行为和下标运算相似,但是如果给出的下标无效,
at 函数将会抛出 out_of_range 异常;

pop_front 操作通常与 front 操作配套使用,实现以栈的方式处理容器:

     while (!ilist.empty()) {
         process(ilist.front()); // do something with the current top of ilist
         ilist.pop_front();      // done; remove first element
     }
pop_front 和 pop_back 函数的返回值并不是删除的元素值,而是 void。要获取删除的元素值,
则必须在删除元素之前调用 notfront 或 back 函数。

使用find结合删除操作
string searchValue("Quasimodo");
     list<string>::iterator iter =
            find(slist.begin(), slist.end(), searchValue);

     if (iter != slist.end())
          slist.erase(iter);

赋值和 assign 操作使左操作数容器的所有迭代器失效。swap 操作则不会使迭代器失效。完成 swap 操作后,
尽管被交换的元素已经存放在另一容器中,但迭代器仍然指向相同的元素。
swap函数的效率更高一些;
关于 swap 的一个重要问题在于:该操作不会删除或插入任何元素,而且保证在常量时间内实现交换。
由于容器内没有移动任何元素,因此迭代器不会失效。
swap 操作实现交换两个容器内所有元素的功能。要交换的容器的类型必须匹配:操作数必须是相同类型的容器,
而且所存储的元素类型也必须相同。

类型不同的情况就必须使用assign函数
assign 操作首先删除容器中所有的元素,然后将其参数所指定的新元素插入到该容器中。与复制容器元素的构造函数一样,
如果两个容器类型相同,其元素类型也相同,就可以使用赋值操作符(=)将一个容器赋值给另一个容器。如果在不同(或相同)类型
的容器内,元素类型不相同但是相互兼容,则其赋值运算必须使用 assign 函数。例如,可通过 assign 操作实现
将 vector 容器中一段 char* 类型的元素赋给 string 类型 list 容器。

弄清楚容器的 capacity(容量)与 size(长度)的区别非常重要。size 指容器当前拥有的元素个数;
而 capacity 则指容器在必须分配新存储空间之前可以存储的元素总数。
capacity的值可以有reserve函数改变;
对于vector容器,只要capacity没有用完,就不会重新分配额外的存储空间;

在 deque 容器首部或尾部插入元素不会使任何迭代器失效,而首部或尾部删除元素则只会使指向
被删除元素的迭代器失效。在 deque 容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器都失效。

如果无法确定某种应用应该采用哪种容器,则编写代码时尝试只使用 vector 和 lists 容器都提供的操作:使用迭代器,
而不是下标,并且避免随机访问元素。这样编写,在必要时,可很方便地将程序从使用 vector 容器修改为使用 list 的容器。

对于存储有限的程序设计,使用deque的优势:FIFO
即把读入的数据存储到队列的尾部,优先处理队首的元素,处理完成后删除;

如果在查找字符串时希望匹配任意指定的字符,则实现起来稍微复杂一点。例如,下面的程序要在 name 中寻找并定位第一个数字:

     string numerics("0123456789");
     string name("r2d2");
     string::size_type pos = name.find_first_of(numerics);
     cout << "found number at index: " << pos
          << " element is "  << name[pos] << endl;

默认的 stack 和 queue 都基于 deque 容器实现,而 priority_queue 则在 vector 容器上实现。在创建适配器时,通过将一个
顺序容器指定为适配器的第二个类型实参,可覆盖其关联的基础容器类型:

     // empty stack implemented on top of vector
     stack< string, vector<string> > str_stk;

     // str_stk2 is implemented on top of vector and holds a copy of svec
     stack<string, vector<string> > str_stk2(svec);

stack 适配器所关联的基础容器可以是任意一种顺序容器类型。因此,stack 栈可以建立在 vector、list 或者 deque 容器之上。
而 queue 适配器要求其关联的基础容器必须提供 push_front 运算,因此只能建立在 list 容器上,而不能建立在 vector 容器上。
priority_queue 适配器要求提供随机访问功能,因此可建立在 vector 或 deque 容器上,但不能建立在 list 容器上。

 
 

 

 

 

 

 

抱歉!评论已关闭.