STL面试题
一、讲讲STL的六大组件
1、容器:存放数据的各种数据结构,STL 容器是⼀种 class template
2、迭代器:为了访问容器中的元素,是一种泛型指针,迭代器是⼀种将 operator *, operator ->, operator++, operator-- 等指针相关操作予以重载的class template
3、算法:可以操作容器中的元素,如 sort、search、copy,STL 算法是⼀种 function template
4、适配器:容器适配器(stack、queue)、算法适配器(mem_fn)、迭代器适配器(插入迭代器)
5、函数对象(仿函数):仿函 数是⼀种重载了 operator() 的 class 或class template
6、空间适配器:负责空间的申请与释放,实现了动态空间配置、空间管理、空间释放的 class template
二、vector 及其底层原理
vector 是封装了动态大小数组的顺序容器,它能够存放各种类型的对象,可以简单的认为,vector是一个能够存放任意类型的动态数组
vector采用线性连续空间,以两个迭代器 start 和 finish 分别指向配置得来的连续空间中目前已被使用的空间 ,迭代器 end_of_storage 指向整块连续空间(含备用空间)的尾端。
vector在调⽤ push_back 插⼊新元素的时候,⾸先会检查是否有备⽤空间,如果有就直接在备⽤空间上构造元素,并调整迭代器 finish ,如果超过自身最大的容量,vector 则将自身的容量扩充为原来的两倍 (重新配置空间、元素移动、释放旧的空间)
内存扩充操作:如果原空间⼤⼩为 0 则分配 1 个元素,如果⼤于 0 则分配原空间两倍的新空间,然后把数据拷⻉过去
三、vector迭代器失效问题
迭代器底层就是一个指针,迭代器失效就是指迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃
造成迭代器失效的操作:resize、insert、erase、push_back 等会引起底层空间改变的操作
vector<int> vec = {1, 2, 3, 4, 5}; vector<int>::iterator it; for(it = vec.begin(); it != vec.end(); it++){ if(*it > 2){ vec.erase(it); }
当前元素的iterator被删除后,其后的所有元素的迭代器都会失效,因为对其进行erase操作时,其后的每一个元素都会向前移一个位置,已经失效的迭代器不能进行++操作,所以程序中断了
解决:所以只要我们每次执行删除操作的时候,将下一个有效迭代器返回就可以顺利执行后续操作了
vector<int> vec = {1, 2, 3, 4, 5}; vector<int>::iterator it; for(it = vec.begin(); it != vec.end(); ){ if(*it > 2){ it = vec.erase(it); } it++;
凡是涉及到扩容操作,都有可能引起迭代器失效,因为vector扩容是分配一个新的数组,然后全部元素移到新的数组中
vector<int> vec = { 1, 2, 3, 4, 5 }; vector<int>::iterator it = vec.begin(); while (it != vec.end()) { if (*it % 2 == 0) { it = vec.insert(it, 66); it++; } it++; }
在使用push_back对vector进行构造的时候,vector的容量capacity(与size有区别)会根据压入元素的数量进行内存的自动重新分配,这时候iterator会因为vector存储空间的变化而失效,要在每次
扩容后更新 begin 迭代器的位置
void test2() { vector<int> vec; cout << "容量" << vec.capacity() << "大小" << vec.size() << endl; vector<int>::iterator it; int i = 0; for (i = 0; i < 1000; i++) { vec.push_back(i); it = vec.begin(); //更新迭代器的位置 } cout << "容量" << vec.capacity() << "大小" << vec.size() << endl; }
四、push_back 和 emplace_back 的区别
push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。
五、空间配置器
在 C++ ⾥,当我们调⽤ new 和 delete 进⾏对象的创建和销毁的时候,也同时会有内存配置操作和释放操作
为了精密分⼯,STL allocator 决定将这两个阶段操作区分开来。
- 对象构造由 ::construct() 负责;对象析构由 ::destroy() 负责。
- 内存配置由 alloc::allocate() 负责;内存释放由 alloc::deallocate() 负责;

1、构造与析构
在 STL ⾥⾯,construct() 函数接受⼀个指针 P 和⼀个初始值 value,该函数的⽤途就是将初 值设定到指针所指的空间上。
destroy() 函数有两个版本,第⼀个版本接受⼀个指针,准备将该指针所指之物析构掉,第⼆个版本接受 first 和 last 两个迭代器,将[first,last)范围内的所有对象析构掉
#include <new.h> //使用placement new template <class T1,class T2> inline void construct(T1*p,const T2& value ) { new (p)T1( value); // placement new; 调用T1::T1( value ) }
注:placement new 就是在用户指定的内存位置上构建新的对象,这个过程不需要额外分配内存
template <class T> inline void destroy (T* pointer) { pointer->~T( ); //调用dtor ~T( ) }
2、内存的配置与释放

浙公网安备 33010602011771号