以上是本课程的学习路线,有删减

流 Stream

stream 相当于缓冲区 buffer,在不同物件中传输数据

构造 stringstream

#include <iostream>
#include <sstream>
#include <string>
int main() {
std::istringstream iss("Initial");
std::ostringstream oss("Initial");
std::string s;
iss >> s;
oss << s;
return 0;
}

四个 bits:

  1. Good:准备好读写
  2. Fail:之前的操作失败了
  3. EOF:之前的操作到达了 buffer 的末尾
  4. Bad:外部错误

通常检查 EOFFail 位的状态

不要大量使用 std::endl,因为每次使用时都会清除一次 buffer,导致效率低下,改为 \n

还有很多 manipulator 可供使用,例如控制格式的 endlhexsetprecisionfixedfillboolalpha,还有调整指针在 buffer 中的位置的 iss.tellp()oss.tellg()iss.seekp(pos)oss.seekg(pos)

类型 Type

auto 可以用于代替比较长且类型不重要的类型名。

pair 可用于两个变量,tuple 为三个

#include <string>
#include <tuple>
#include <utility>
int main() {
// 定义变量
std::pair<double, int> prices = std::make_pair(3.4, 5);
std::tuple<int, int, std::string> values = std::make_tuple(3, 4, "hi");

// 访问变量
prices.first = prices.second;
get<0>(values) = get<1>(values);

// 结构化绑定快速提取所有组成部分
auto [a, b] = prices;
auto [x, y, z] = values;
return 0;
}

传递函数参数时,若数据量较大,可使用&引用变量,而不是复制一份。

c++ 初始化方法过多,可使用统一初始化法,即使用初始化表 initializer_list,例如 vector<int> vec{1, 2, 3};Course now{"CS106L", {15, 30}, {16, 30}};,结构体内的变量按照定义顺序赋值。

注意
vector<int> vec(3); // vec = {0, 0, 0} vector<int> vec{3}; // vec = {3}

序列容器 Sequence Container

STL内容

包括 vectordequelist(双链表),arrayforward_list(单链表)

因为本质上使用的是 vector 和 deque,所以 stackqueue 也被成为容器适配器 Container Adaptor

关联容器 Associative Container 和 迭代器 Iterator

包括 mapsetunordered_mapunordered_set

unordered_map 和 map 的区别

  1. 实现不同
    unordered_map 底层是用哈希表实现的
    map 底层是用红黑树实现的
  2. 性能不同
    unordered_map 是不按键值排序的,插入的时间是 O(logn),查询时间是 O(1)
    map 是按键值排序的,插入的时间是 O(logn),查询时间是 O(logn)

高级容器 Advanced Container 有 multi_mapmulti_set

迭代器 Iterator用于访问容器

for(auto it:v) 的本质就是使用迭代器

iterator 有 5 种类型:

  1. Input 输入
  2. Output 输出
  3. Forward 前向
  4. Bidirectional 双向
  5. Random Access 随机读写

关系如下:

模板 Template

template <typename T>
T my_max(T a, T b) {
return a > b ? a : b;
}

实质是在编译时智能将 T 替换为 intdouble等,这种叫作泛型函数 generic function

但是类型 T 必须满足一定条件,例如可比较大小,但没有写出来,这叫作隐式接口 implicit interface

C++20 提供的 Concept 可将隐式接口转化为显示接口 explicit interface

函数 Function 和算法 algorithm

lambda 函数相当于写在一行内的轻量化函数

auto func=[捕捉规则](参数)->返回值类型(可选){
//body
};

predicate 是一个接收一些参数并返回一个 boolean 值的函数,例如:

#include <iostream>
template <typename T, typename Pred>
T my_max(T a, T b, Pred cmp) {
return cmp(a, b) ? a : b;
}
bool cmp1(int a, int b) {
return a > b;
}
int main() {
int a = 10, b = 20;
auto cmp2 = [](int a, int b) -> bool {
return a > b;
};
std::cout << my_max(a, b, cmp1) << std::endl;
std::cout << my_max(a, b, cmp2) << std::endl;
return 0;
}

这样即可将函数作为参数传递。

算法有 sortnth_elementstable_partitioncopy_ifremove_if

运算符 Operator

c++ 中可重载的运算符:

算术 关系 逻辑 增加 内存 其它
+ += & == << && ++ -> ()
- -= | != >> || -- ->* []
* *= ~ < <<= ^ new ,
/ /= ! > >>= &= new [] =
<= |= delete
>= ^= delete []
<=>

重载时遵循以下规则:

  1. []()->=++ 重载为成员函数
  2. << 重载为非成员函数
  3. 若两个值平等,如 +,重载为成员函数;若不平等,如 +=,重载为非成员函数

重载了 < 后可将剩下几个关系符一起重载:

inline bool operator< (const X& lhs, const X& rhs) { /* do actual comparison */ }
inline bool operator> (const X& lhs, const X& rhs) { return rhs < lhs; }
inline bool operator<=(const X& lhs, const X& rhs) { return !(lhs > rhs); }
inline bool operator>=(const X& lhs, const X& rhs) { return !(lhs < rhs); }

inline bool operator==(const X& lhs, const X& rhs) { /* do actual comparison */ }
inline bool operator!=(const X& lhs, const X& rhs) { return !(lhs == rhs); }

特殊的成员函数 Special Function

以下特殊的成员函数一般要重载:

  1. 没有参数的生成对象
  2. 以已有的对象生成另一个对象
  3. 复制并替换原有对象的内容
  4. 销毁

也可以 函数声明 = delete; 销毁特定函数

移动语义 Move Semantic

l-value 是有名称的表达式,可以用 & 获取地址;
r-value 是没有名称的表达式,是临时的值,无法用 & 获取地址,只能出现在赋值语句右边。

例如 swap() 函数可以优化:

template <typename T>
void swap(T& a, T& b) {
T temp = std::move(a);
a = std::move(b);
b = std::move(temp);
}

继承 Inheritance

class Drink {
public:
virtual void make() = 0;
};
class Tea : public Drink {
public:
void make() {
/*实现*/
}
};

资源获取就是初始化 RAII 和智能指针 Smart Pointer

防止因程序意外停止运行而导致的内存泄漏,解决方法的本质为调用时构造对象,后析构对象

不要这么做:

ifstream input();
input.open("in.txt");
/*实现*/
input.close();

改为:istream input("in.txt");

同样,避免使用 newdelete,使用 unique_ptrshared_ptrweak_ptr 等(在头文件 memory 中),例如std::unique_ptr<int> p = std::make_unique<int>();

模板元编程 Template Metaprogramming

对值的计算:

int s = 3;
int triple = 3 * s;
int result = foo(triple);
bool equals = (result == 0);
if (equals)
exit(1);

对于类型,有:

using S = int;
using cl_ref = const S&;
using result = std::remove_reference<cl_ref>::type;
constexpr bool equals = std::is_same<result, const int>::value;
if constexpr (equals)
exit(1);