现代C++程序应该使用标准库容器,而不是更原始的数据结构,例如内置数组。
新标准库容器的性能几乎肯定与最精心优化过的同类数据结构一样好。
当我们用一个对象来初始化容器时,或将一个对象插入到容器中时,实际上放入到容器中的是对象值的拷贝,而不是对象本身。
- 容器选择原则:
- 除非你有很好的理由选择其他容器,否则应使用vector;
- 如果你的程序有很多小的元素,且空间的额外开销很重要,则不要使用list或forward_list;
- 如果程序要求随机访问元素,应使用vector或deque;
- 如果程序需要在头尾位置插入或删除元素,而不会再中间位置插入或删除,使用deque;
- 如果程序只有在读取输入时才需要在中间位置插入元素,随后需要随机访问元素,则:
- 首先确定是否真的需要在容器中间位置添加元素。(可以在vector中追加数据,然后sort重排)
- 如果必须添加元素,则考虑输入阶段使用list;一旦完成,将list的内容copy到一个vector中。
Best Practice:如果不确定应该使用哪种容器,那么可以在程序中只使用vector和list的公共操作:使用迭代器。不使用下标操作,避免随机访问。
为了创建一个容器为另一个容器的拷贝,两个容器的类型及其元素类型必须匹配。不过,当传递迭代器参数来拷贝一个范围时,就不要求容器类型是相同的了,而且元素类型可以转换即可。
1 list<string> authors = { "Milton","Shakespeare","Austen" }; 2 vector<const char*> articles = { "a", "an","the" }; 3 4 list<string> list2(authors);//正确 5 vector<string> authors2(authors);//错误,容器类型不匹配 6 list<string> words(articles.begin(), articles.end());//正确 7 list<const string> ls(authors);//错误
虽然内置数组不能进行copy或者对象赋值工作,但array并没有这种限制。
由于右边运算对象的大小可能与左边运算对象的大小不同,因此array类型不支持assign,也不允许用花括号列表来赋值(但是可以初始化)
1 array<int, 4> digits = { 0,1,2,3 }; 2 array<int, 4> copy = digits;//正确 3 4 array<int, 4> a1 = { 0,1,2,3 }; 5 a1 = { 0,1,2,3 };//错误
swap:除array外,交换两个容器内容的操作会很快——元素本身并未交换,swap只是交换两个容器的内部数据结构。swap两个array会真正交换它们的元素。
- 向容器中插入/删除元素
push_back(t), push_front(t),返回void;
insert(p,t), insert(p,n,t), insert(p,b,e), insert(p,il) 实在迭代器p元素之前插入元素,返回指向新添加的(第一个)元素的迭代器。
emplace_front(args), emplace_back(args),emplace(p,args)这些操作构造而不是拷贝元素。是将参数传递给元素类型的构造函数。emplace成员使用这些参数在容器管理的内存空间中直接构造元素。而调用push_back则会创建一个局部临时对象,并将其压入容器中。
- 删除元素
pop_back(), pop_front(), clear()返回void;
erase(p),erase(b,e)删除元素,返回一个指向(最后)被删元素之后元素的迭代器;
- forward_list
没有简单办法来获得前驱,所以其删除/插入都是after版本。
insert_after(p,t),insert_after(p,n,t),insert_after(p,b,e),insert_after(p,il),emplace_after(p,args)在迭代器p之后插入元素,返回一个指向最后一个插入元素的迭代器
erase_after(p), erase_after(b,e)删除p指向的位置之后的元素,返回一个指向北山元素之后元素的迭代器。
- string的数值转换
新标准引入了多个函数,可以实现数值数据与标准库string之间的转换
to_string(val),
stoi/stoul/stol/stoll/stoull(s,p,b):返回s起始子串(表示整数部分)的数值,b表示基数,默认为10。P是size_t指针,用来保存s第一个非数值字符的下标。
stof/stod/stold(s,p)