https://gitee.com/quicksands/stl-source-code-analysis
C++11关键字:auto和decltype
- auto:占位符类型说明符
- 对于变量,
auto x = expr;
从初始化器推导类型
- 对于变量,
- decltype说明符
decltype (expr)
声明从表达式得到的类型
容器
- 容器是储存其他对象的对象。简单来说,每个容器提供了一种适配大部分类型的数据结构。
- 容器分为四种:
- 序列式容器:
<array>
<deque>
<forward_list>
<list>
<vector>
- 关联式容器:
<map>
<set>
- 无序关联式容器:
<unordered_map>
<unordered_set>
- 容器适配器:
<queue>
<stack>
- 序列式容器:
序列式容器
顺序容器 | 顺序容器实现能按顺序访问的数据结构 |
---|---|
array(c++11) | 静态(固定长度) 的连续数组 (类模板)![]() |
vector | 动态的连续数组 (类模板)Implementation |
deque | 双端队列 (类模板)Implementation |
forard_list(c++11) | 单链表 (类模板) |
list | 双链表 (类模板)Implementation |
eg
- vector
vector<T>
是动态的连续数组。- 动态指它的长度是可变的;连续指它的元素可用T*访问。
- 它实现了两种元素访问
- operator [],注意:不检查下标是否越界
- 访问元素函数(返回元素的左值):front,at(int),back。其中,at检查下标越界,越界则抛出异常。
- 实现了列表初始化(直接列表和复制列表)
- 使用迭代器
- 迭代器(Iterator)是用于遍历容器元素的指针对象的包装。
- 单向迭代器实现了以下运算符重载
- operator ++,==, != , * 等,例如:++ 表示取容器中的下一个元素
- 容器会提供一个或多个迭代器实现。
- 例如:
- vector提供正向和反向的迭代器。
- 通过成员函数begin(),end()返回正向迭代器对象实例。
- 通过成员函数rbegin(),rend()返回反向迭代器对象实例。
- 例如:
关联式容器
类名 | 说明 | 所在头文件 |
---|---|---|
map | 通过键进行元素存取的关联数组 | <map> |
multimap | 支持重复键的关联数组 | <map> |
set | 任何元素的集合 | <set> |
multiset | 可以重复的集合 | <set> |
unordered_map | 无序的map,类似于哈希表 | <unordered_map> |
unordered_set | 无序的set,类似于哈希表 | <unordered_set> |
- std::pair
- std::map的某些函数使用了中的类std::pair,pair<T1, T2>代表一个由类型T1和类型T2组成的有序对。
- 可以直接用构造函数
std::pair<T1, T2> (v1, v2)
进行构造,也可以用make_pair进行构造:auto p = make_pair<v1,v2>;
- 通过
p.first
访问第一个元素,通过p.second
访问第二个元素
map
multimap
set
适配器
stack
queue
priority_queue
迭代器
- 迭代器是每种容器各自定义的一个或多个不同于容器的类,比如
vector<T>::iterator
,它主要用于访问、修改、增加、删除容器中的元素。 - 按照功能的不同,C++17之前的迭代器分为:
- LegacyInputIterator(输入迭代器)
- LegacyOutputIterator(输出迭代器)
- LegacyForwardIterator(单向迭代器)
- LegacyBidirectionalIterator(双向迭代器)
- LegacyRandomAccessIterator(随机迭代器)
- C++17加入了LegacyContiguousIterator(连续迭代器)
- 失效案例分析
vector<int> ivv1 {1,2,4,5,3};
for (auto it = ivv1.begin(); it != ivv1.end(); it++) {
if (*it == 3) ivv1.erase(it);
}
-
在 for 循环中,当你调用 ivv1.erase(it) 删除元素 3 后,当前迭代器 it 就失效了(即不再指向合法位置);
-
但是 for 循环的条件中仍然执行了 it++,这导致你对一个已经失效的迭代器自增,这属于未定义行为(UB);
-
结果可能是程序崩溃、输出错误结果,或“看起来没错但风险极高”。
修正代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> ivv1 {1,2,3,4,5};
for (auto it = ivv1.begin(); it != ivv1.end(); ) {
if (*it == 3)
it = ivv1.erase(it); // 返回新的有效迭代器
else
++it;
}
for (auto x : ivv1) cout << x << ",";
cout << endl;
}
算法
#include<iostream>
#include<functional>
using namespace std;
int twox_add_threey(int x,int y){
return 2*x+3*y;
}
class Foos{
public:
static int twox_add_threey(int x,int y){
return 2*x+3*y;
}
};
class Food{
public:
int twox_add_threey(int x,int y){
return 2*x+3*y;
}
};
class Func{
private:
int a,b;
public:
Func(int _a=0,int _b=0):a(_a),b(_b){}
int operator()(int x,int y){
return a*x+b*y;
}
};
void callback_client(std::function<int(int,int)> f,int a,int b){
cout<<f(a,b)<<endl;
}
int main(){
cout<<"普通函数回调:";
callback_client(twox_add_threey,1,2);
cout<<"类的静态成员函数回调:";
callback_client(Foos::twox_add_threey,1,2);
cout<<"类的动态成员函数回调:";//动态成员函数需要对象才能调用
Food food;
callback_client(std::bind(&Food::twox_add_threey,&food,std::placeholders::_1,std::placeholders::_2),1,2);
callback_client(std::bind(food.twox_add_threey,&food,std::placeholders::_1,std::placeholders::_2),1,2);
callback_client([&food](int x,int y){return food.twox_add_threey(x,y);},1,2);
cout<<"函数对象回调:";callback_client(Func(2,3),1,2);
cout<<"匿名函数回调:";callback_client([](int x,int y){return 2*x+3*y;},1,2);
return 0;
}