C++11 新特性之容器相关特性

前三篇在这里:
C++11新特性之新类型与初始化:  http://blog.jobbole.com/102728/
C++11新特性之类型推断与类型获取:  http://blog.jobbole.com/104559/
C++11新特性之lambda:http://blog.jobbole.com/104548/

这是C++11新特性介绍的第四部分,涉及到C++11这次更新中与容器有关的新特性。
不想看toy code的读者可以直接拉到文章最后看这部分的总结。

cbegin和cend

原来的begin和end返回的iterator是否是常量取决于对应的容器类型,但是有时,即使容器不是常量类型,我们也希望获得一个const_iterator,以避免不必要的修改行为。C++11新标准中提供了cbegin和cend函数,无论容器类型,都固定返回const_iterator。

标准库的 begin 和 end

C++11新标准提供了begin和end函数,可以对普通数组使用,获得头指针和尾指针。

新的赋值方式

C++11允许使用一个{}包围的初始值列表来进行复制。如果等号左侧是个容器,那么怎么赋值由容器决定。

initializer_list

C++11新标准中新增了initializer_list类型,其实在之前介绍初始化的那篇文章中,使用vector v = {0, 1, 2, 3, 4}这种初始化形式时,就隐式的使用了initializer_list:每当在程序中出现一段以{}包围的字面量时,就会自动构造一个initializer_list对象。

另外,initializer_list的另一个作用就在于作为函数的形参,这样的函数可以方便的传入以{}包围的不定长列表:

但是,需要注意的是,initializer_list中的元素是只读的。

array

C++11标准中提供了定长数组容器array,相比于普通数组更安全、更易使用。array是定长数组,所以不支持诸如插入、删除等改变容器大小的操作,但是可以对元素进行赋值改变其值。

forward_list

C++11标准中增加了新的容器forward_list,提供了一个快速的、安全的单向链表实现。因为是单向链表,所以也就没有rbegin、rend一类的函数支持了。

同样是因为单向链表的缘故,无法访问到给定元素的前驱,所以没有提供insert函数,而对应提供了一个insert_after函数,用于在给定元素之后插入节点。erase_after、emplace_after同理。

swap

新标准中提供了非成员版本的swap操作,此操作对array容器,会交换元素的值;对其他容器,则只交换容器的内部结构,并不进行元素值的拷贝操作,所以在这种情况下是非常迅速的。

正因如此,当swap array后,原来array上的迭代器还依然指向原有元素,只是元素的值变了;
而swap非array容器之后,原来容器上的迭代器将指向对方容器上的元素,而指向的元素的值却保持不变。

emplace

emplace操作将使用接受的参数构造一个对应容器中的元素,并插入容器中。这一点,使用普通的insert、push操作是做不到的。

shrink_to_fit

一般可变长容器会预先多分配一部分内存出来,以备在后续增加元素时,不用每次都申请内存。所以有size和capacity之分。size是当前容器中存有元素的个数,而capacity则是在不重新申请内存的情况下,当前可存放元素的最大数目。而shrink_to_fit就表示将capacity中的多余部分退回,使其回到size大小。但是,这个函数的具体效果要依赖于编译器的实现……

无序关联容器

C++11新标准中引入了对map、set等关联容器的无序版本,叫做unorderer_map\/unordered_set。

无序关联容器不使用键值的比较操作来组织元素顺序,而是使用哈希。这样在某些元素顺序不重要的情况下,效率更高。

tuple

熟悉python的程序员应该对tuple都不陌生,C++11中也引入了这一数据结构,用于方便的将不同类型的值组合起来。

可以通过如下方式,获取tuple中的元素、tuple的长度等:

总结

  1. cbegin和cend提供了固定获取const_iterator的方式。
  2. begin和end用于普通数组获得首尾指针。
  3. 可以使用{}包围的初始值列表进行赋值。
  4. 增加initializer_list类型用于方便的使用{}包围的不定长列表。
  5. 增加新的定长数组容器array 单向链表容器forward_list。
  6. 增加非成员函数版本的swap操作。对array swap只交换元素值,而容器的结构不变;对其他容器则只改变容器数据结构,而元素值不变。
  7. 增加emplace操作用于将参数传递给构造函数构造元素并插入容器。
  8. 增加shrink_to_fit函数用于退回多余的空间。
  9. 增加无序关联容器。
  10. 增加tuple容器。

完整代码详见container.cpp

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

1 5 收藏 1 评论

关于作者:usher2007

游戏开发 C/C++ Python Linux 个人主页 · 我的文章 · 9 ·    

相关文章

可能感兴趣的话题



直接登录
最新评论
  • 伯小乐 小编 2016/08/20

    少跟网线设置路由 在伯乐在线「CPP开发者」微信的评论:

    “每当在程序中出现一段以{}包围的字面量时,就会自动构造一个initializer_list对象。” 这段话是错误的,这个要看情况,假如将{}包含的字段当做实参传递给一个接受 std::initializer_list 作为参数的函数,那这句话是正确的,在使用std ::initializer_list {}调用构造函数也要看列表中的数据是否跟某个构造函数的参数一一对应,此时也只是相当于使用“()”方式调用构造函数,生成对象,至于传统的数组也还可以使用{}来初始化,此时更不可能生成std::initializer_list 对象。

    生成std::initializer_list对象的过程中构建了一个临时数组,并将{}列表中的元素拷贝到数组中,应该{}中的元素必须可拷贝,生成的过程也相对有些消耗,因此std::initializer_list 对象的生成要考虑考虑拷贝的性能,另外使用它的时候也要注意底层关联的临时数组的生命期!一般情况下,为了保存数据,接受生成的std::initializer_list 的一方还要二次拷贝数据!

跳到底部
返回顶部