vector容器的几个要点
来源:互联网 发布:2016易语言源码大全 编辑:程序博客网 时间:2024/06/06 09:29
1. insert插入和emplace的区别
emplace操作是C++11新特性,新引入的的三个成员emlace_front、empace 和 emplace_back,这些操作构造而不是拷贝元素到容器中,这些操作分别对应push_front、insert 和push_back,允许我们将元素放在容器头部、一个指定的位置和容器尾部。
两者的区别
当调用insert时,我们将元素类型的对象传递给insert,元素的对象被拷贝到容器中,而当我们使用emplace时,我们将参数传递元素类型的构造函数,emplace使用这些参数在容器管理的内存空间中直接构造元素。
insert插入的数据需要经过 栈->寄存器->内存 ,而emplace只需要 寄存器->内存。
例子
假定d是一个Date类型的容器。
//使用三个参数的Date构造函数,在容器管理的内存空间中构造新元素。 d.emplace_back(“2016”,”05”,”26”);//错误,push_back没有这种用法 d.push_back(“2016”,”05”,”26”);//push_back()创建一个临时对象,然后将临时对象拷贝到容器中 d.push_back(Date(“2016”,”05”,”26”));
通过例子发现,使用c++11新特性emplace向容器中添加新元素,在容器管理的内存空间中构造新元素,与insert相比,省去了构造临时对象,减少了内存开销。
2.iterator迭代器失效问题
2.1 插入失效
#include<iostream>#include<vector>using namespace std;int main(){ vector<int> v; v.push_back(1); std::vector<int>::iterator iter1 = v.begin(); v.push_back(1); int n = *iter1; cout << n << endl; return 0;}
上面的代码运行时崩溃,就是因为迭代器iter1在vector push_back新值后失效了。切记!
但是为什么会失效?
如果我先预先resize足够大,那么会如何呢?
#include<iostream>#include<vector>using namespace std;int main(){ vector<int> v; v.resize(4); v.push_back(1); std::vector<int>::iterator iter1 = v.begin(); v.push_back(1); int n = *iter1; cout << n << endl; return 0;}
上面的代码正常运行,因为之前resize了足够的空间,即迭代器不会失效。
我们就已给vector push_back两个元素为例。resize(1), resize(2), resize(3)程序还是会崩溃。还是容量不足,导致vector重新分配内存,而导致迭代器失效。
参考博客:http://blog.csdn.net/wangshubo1989/article/details/50334297
2.2删除失效
#include <iostream>#include <vector>using namespace std;typedef vector<int> Vec;typedef vector<int>::iterator VecIt;void print(Vec &v){ VecIt it; for(it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl;}void deleteValueFromVector(Vec &v, int n = 5){ VecIt it; for(it = v.begin(); it != v.end(); it++) { if(0 == *it % n) { v.erase(it); } }}int main(){ Vec v; int i = 0; for(i = 0; i < 21; i++) { v.push_back(i); // 不能再傻傻地用下标了 } print(v); deleteValueFromVector(v); // 程序崩溃 print(v); return 0;}
运行程序, 结果程序也崩溃, 可见, vector删除也存在迭代器失效的问题, 怎么改呢? 如下:
#include <iostream>#include <vector>using namespace std;typedef vector<int> Vec;typedef vector<int>::iterator VecIt;void print(Vec &v){ VecIt it; for(it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl;}void deleteValueFromVector(Vec &v, int n = 5){ VecIt it; for(it = v.begin(); it != v.end(); /*不能再自增了*/) { if(0 == *it % n) { v.erase(it); // vector元素自动向前挪动了(关联的map容器元素不会自动挪动), 所以不能再把it进行++了 } else { it++; } }}int main(){ Vec v; int i = 0; for(i = 0; i < 21; i++) { v.push_back(i); // 不能再傻傻地用下标了 } print(v); deleteValueFromVector(v); // 程序ok print(v); return 0;}
结果为:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 2 3 4 6 7 8 9 11 12 13 14 16 17 18 19
可见, vector迭代器失效的问题也不容忽视。
3.Capacity容量的增长方式
下面我们截取了VS2017编译器中的关于容量增长的源码:
size_type _Calculate_growth(const size_type _ Newsize) const { // given _Oldcapacity and _Newsize, calculate geometric growth const size_type _Oldcapacity = capacity(); if (_Oldcapacity > max_size() - _Oldcapacity / 2) { return (_Newsize); // geometric growth would overflow } const size_type _Geometric = _Oldcapacity + _Oldcapacity / 2; if (_Geometric < _Newsize) { return (_Newsize); // geometric growth would be insufficient } return (_Geometric); // geometric growth is sufficient }
第一种情况:_Oldcapacity > max_size() - _Oldcapacity / 2 : 当旧容量大于(最大的可能的元素个数 - 旧容量/2) ,直接返回Newsize大小的容量第二种情况:_Geometric = _Oldcapacity + _Oldcapacity / 2; 即1.5倍旧容量小于Newsize,返回Newsize大小的容量。第三种情况: 排除以上2种情况,返回1.5倍旧容量
参考博客:
map和vector的迭代器失效问题:
http://www.cnblogs.com/yuanshuang/p/5777905.html
实战c++中的vector系列–可怕的迭代器失效(vector重新申请内存):
http://blog.csdn.net/wangshubo1989/article/details/50334297
C++11新特性emplace操作:
http://blog.csdn.net/penghuicheng/article/details/51505625
- vector容器的几个要点
- STL要点学习(1)--vector容器
- C/C++知识要点2——STL中Vector、Map、Set容器的实现原理
- Ant的几个要点
- UIScrollView的几个要点
- Ant的几个要点
- Netty的几个要点
- HashMap 的几个要点
- vector容器的初使化
- vector容器的使用方法
- 容器Vector的使用
- 容器vector的入门
- 容器vector的函数
- vector 容器的使用方法
- vector 容器的用法
- vector 容器的用法
- c++的vector容器
- vector容器的实现
- memcpy与strcpy区别
- 7.7--SSH学习之Hibernate Session
- POJ 2253 Frogger【SPFA变形】
- 机器学习
- MySQL 5.7 command line client指令总结
- vector容器的几个要点
- ubuntu 命令行模式和图形界面切换
- java继承简述及方法覆盖
- Python从入门到精通-简介
- 手把手教你配置Ubuntu server服务器_5
- PSR规范--php编码规范
- java学习路线参考
- Python探索记(14)——字符串、列表、元组、字典与运算符相关的操作
- Vuejs2.0 小应用