容器,容器适配器复习
深浅拷贝
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规 。
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。
深拷贝:给每个对象独立分配资源,保证多个对象不会因共享资源而造成多次释放造成程序崩溃的问题。
capacity
vs下capacity是按1.5倍增长的,g++是按2倍增长的。
reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
resize在开空间的同时还会进行初始化,影响size。
vector 迭代器失效问题
1.resize、reserve、insert、assign、push_back等以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。
2.erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。
vector迭代器失效解决办法
在使用前,对迭代器重新赋值即可 。
删除的时候erase()函数会返回删除数据的下一个数据 。
vector不用memcpy拷贝的原因
memcpy的拷贝实际是浅拷贝 。
list的迭代器失效
因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响 。
什么是适配器
适配器是一种设计模式 ,该种模式是将一个类的接口转换成客户希望的另外一个接口 。
容器适配器
容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素。
stack 的底层使用什么实现
默认deque(双端队列),vector也可以胜任。
queue的底层用什么实现
默认deque(双端队列),list也可以
priority_queue 队列
优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的 。
标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
默认情况下priority_queue是大堆 。
如果要创建小堆,将第三个模板参数换成greater比较方式 ;
priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载。
deque (双端队列)
deque(双端队列):是一种双开口的"连续"空间的数据结构 。
双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高 。
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组 。
为什么选择deque作为stack和queue的底层默认容器
- stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
- 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。
什么是分离编译
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式 。
函数模板的优缺点
优点:1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
2. 增强了代码的灵活性
缺点:1. 模板会导致代码膨胀问题,也会导致编译时间变长
2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误