make_shared
make_shared 是一个函数模板,它的语法
cpp
std::make_shared<类型名>(构造函数的参数)
// 模板参数 函数参数
// make_shared 调用
make_shared<LruNodeType>(Key(), Value());
// 告诉它创建什么 传给构造函数的参数
make_unique
cpp
std::make_unique<类型名>(构造参数)
容器常用函数
cpp
// 1. 大小相关
container.size(); // 返回元素个数
container.empty(); // 是否为空
// 2. 清空
container.clear(); // 删除所有元素
// 3. 迭代器
container.begin(); // 第一个元素的迭代器
container.end(); // 最后一个元素的下一个位置
顺序容器(vector, list, deque)
cpp
vector<int> v;
// 添加
v.push_back(10); // 尾部添加
v.push_front(10); // 头部添加(list支持)
v.insert(pos, 10); // 指定位置插入
// 删除
v.pop_back(); // 删除尾部
v.pop_front(); // 删除头部(list支持)
v.erase(pos); // 删除指定位置
v.erase(begin, end); // 删除范围
// 访问
v[0]; // 下标访问(vector, deque)
v.at(0); // 边界检查的下标访问
v.front(); // 第一个元素
v.back(); // 最后一个元素
- vector(动态数组)
cpp
vector<int> v = {1, 2, 3};
// ✅ 支持
v.push_back(4); // 尾部添加:{1,2,3,4}
v.pop_back(); // 尾部删除:{1,2,3}
v.insert(v.begin() + 1, 10); // {1,10,2,3}
v.erase(v.begin()); // 删除第一个:{10,2,3}
cout << v[0]; // 下标访问:10
cout << v.at(0); // 边界检查访问:10
cout << v.front(); // 第一个元素:10
cout << v.back(); // 最后一个元素:3
// ❌ 不支持
v.push_front(0); // 编译错误!vector没有push_front
v.pop_front(); // 编译错误!vector没有pop_front
vector在内存中是连续存储的,头部插入/删除需要移动所有元素,效率低,所以没提供。
- deque(双端队列)
cpp
deque<int> d = {2, 3, 4};
// ✅ 全部支持!
d.push_front(1); // {1,2,3,4}
d.push_back(5); // {1,2,3,4,5}
d.pop_front(); // {2,3,4,5}
d.pop_back(); // {2,3,4}
cout << d[0]; // 下标访问:2
cout << d.at(0); // 边界检查:2
cout << d.front(); // 第一个:2
cout << d.back(); // 最后一个:4
deque是"分段连续"的,两端操作都很快,所以两端操作都支持
- list(双向链表)
cpp
list<int> l = {2, 3, 4};
// ✅ 支持两端操作
l.push_front(1); // {1,2,3,4}
l.push_back(5); // {1,2,3,4,5}
l.pop_front(); // {2,3,4,5}
l.pop_back(); // {2,3,4}
// ✅ 支持插入删除
auto it = l.begin();
advance(it, 1); // 指向第二个元素
l.insert(it, 10); // {2,10,3,4}
l.erase(it); // 删除10:{2,3,4}
// ❌ 不支持随机访问
cout << l[0]; // 编译错误!list没有[]
cout << l.at(0); // 编译错误!
cout << l.back(); // ✅ 支持,返回最后一个:4
list是链表,节点不连续,无法用下标访问。
- forward_list(单向链表,C++11)
cpp
forward_list<int> f = {2, 3, 4};
// ✅ 只支持头部操作
f.push_front(1); // {1,2,3,4}
f.pop_front(); // {2,3,4}
// ⚠️ 特殊的插入删除(在指定位置之后)
auto it = f.begin(); // 指向2
f.insert_after(it, 10); // 在2后面插入:{2,10,3,4}
f.erase_after(it); // 删除10:{2,3,4}
// ❌ 不支持
f.push_back(5); // 编译错误!
f.pop_back(); // 编译错误!
cout << f.back(); // 编译错误!没有back()
最节省内存的链表,但功能最少
关联容器(map, unordered_map)
cpp
unordered_map<int, string> m;
// 添加/修改
m[1] = "apple"; // 如果key存在就修改,不存在就添加
m.insert({2, "banana"}); // 插入,如果key已存在则失败
// 查找
auto it = m.find(1); // 返回迭代器,找不到返回 m.end()
if (it != m.end()) {
// 找到了
int key = it->first;
string value = it->second;
}
// 检查是否存在
if (m.count(1)) { // 返回1(存在)或0(不存在)
// key存在
}
// 删除
m.erase(1); // 删除key=1的元素
m.erase(it); // 删除迭代器指向的元素
// 遍历
for (auto& [key, value] : m) {
cout << key << ": " << value << endl;
}
关联容器分为两大类:有序关联容器(红黑树)和无序关联容器(哈希表)。
cpp
// 有序关联容器(红黑树实现,自动排序)
set<int> // 集合,元素唯一,自动排序
multiset<int> // 集合,元素可重复,自动排序
map<int, string> // 键值对,键唯一,自动按键排序
multimap<int, string> // 键值对,键可重复,自动按键排序
// 无序关联容器(哈希表实现,无顺序)
unordered_set<int> // 哈希集合
unordered_multiset<int> // 哈希集合(可重复)
unordered_map<int, string> // 哈希映射
unordered_multimap<int, string> // 哈希映射(键可重复)
特殊容器(unique_ptr, shared_ptr)
cpp
unique_ptr<int> u = make_unique<int>(10);
// unique_ptr 特有
if (u) { // 检查是否为空
int value = *u; // 解引用获取值
}
int* raw = u.get(); // 获取原始指针(危险,不推荐)
u.reset(); // 释放资源
u.reset(new int(20)); // 释放原资源,指向新资源
int* released = u.release(); // 放弃所有权,返回原始指针(记得delete)
// shared_ptr 额外功能
shared_ptr<int> s = make_shared<int>(10);
long count = s.use_count(); // 引用计数
// weak_ptr 的赋值操作
weak_ptr<Node> wp;
shared_ptr<Node> sp = make_shared<Node>();
wp = sp; // ✅ weak_ptr 可以从 shared_ptr 赋值(自动转换)
wp = wp2; // ✅ weak_ptr 可以从 weak_ptr 赋值
// 但要访问 weak_ptr 指向的对象:
sp = wp; // ❌ 错误!不能直接转换
sp = wp.lock(); // ✅ 必须用 lock()
C++17的结构化绑定
C++17引入的结构化绑定,可以一次性把pair或tuple的元素拆开;
cpp
for (auto& [key, value] : m) {
// 结构化绑定 (Structured Binding)
cout << key << ": " << value << endl;
}
传统写法(C++11/14)
cpp
unordered_map<int, string> m = {{1, "apple"}, {2, "banana"}};
// 方法1:用迭代器
for (auto it = m.begin(); it != m.end(); ++it) {
int key = it->first;
string value = it->second;
cout << key << ": " << value << endl;
}
// 方法2:用auto(但还是需要.first和.second)
for (auto& pair : m) {
cout << pair.first << ": " << pair.second << endl;
}
新写法(C++17)
cpp
// 直接用结构化绑定拆开
for (auto& [key, value] : m) {
cout << key << ": " << value << endl;
}
// 输出:
// 1: apple
// 2: banana
结构化绑定的更多用法
- 用于 pair
cpp
pair<int, string> p = {1, "hello"};
// 传统方式
int a = p.first;
string b = p.second;
// 结构化绑定
auto [x, y] = p;
cout << x << ", " << y << endl; // 输出:1, hello
- 用于 tuple
cpp
tuple<int, double, string> t = {10, 3.14, "pi"};
// 传统方式
int i = get<0>(t);
double d = get<1>(t);
string s = get<2>(t);
// 结构化绑定
auto [i, d, s] = t;
cout << i << ", " << d << ", " << s << endl; // 10, 3.14, pi
- 用于数组
cpp
int arr[] = {1, 2, 3};
auto [a, b, c] = arr;
cout << a << b << c << endl; // 输出:123
- 用于结构体
cpp
struct Point {
int x;
int y;
};
Point p = {10, 20};
auto [x, y] = p;
cout << x << ", " << y << endl; // 输出:10, 20
初始化
Value value{};
// 这是C++11的统一初始化语法
// 等价于:Value value = Value();
// 如果Value是int,value=0
// 如果Value是string,value=""
// 如果Value是自定义类,调用默认构造函数
奇怪函数
std::thread::hardware_concurrency() 返回CPU核心数(比如8核)
explicit FreqList(int n)
构造函数,explicit 关键字表示不能隐式转换。比如不能写 FreqList list = 5;,必须写 FreqList list(5);
node->pre.expired()
.expired()
weak_ptr 的内置方法:
返回 true:指向的对象已被销毁 / 过期
返回 false:指向的对象仍有效
next 和 prev 函数详解
std::next 和 std::prev 是 C++11 引入的迭代器辅助函数,用于安全地移动迭代器
帮你把迭代器往前或往后移动,特别是 list、set、map 这种不能直接 +1 的容器
list::splice 函数详解
splice 是 C++ std::list 的转移函数,可以把一个链表中的节点直接搬到另一个链表,不复制、不创建新节点,只是改指针。
splice 的四种形式
形式1:转移单个节点
cpp
void splice(const_iterator position, list& other, const_iterator it);
参数:
position:目标位置(插入到这个位置之前)
other:源链表(从哪个链表转移)
it:要转移的节点(指向这个节点的迭代器)
形式2:转移单个节点(自己转移给自己)
cpp
void splice(const_iterator position, list& other, const_iterator it);
// 如果 &other == this,可以重新排列链表
形式3:转移一个范围
cpp
void splice(const_iterator position, list& other,
const_iterator first, const_iterator last);
参数:
position:目标位置
other:源链表
first, last:要转移的范围 [first, last)
形式4:转移整个链表
cpp
void splice(const_iterator position, list& other);
参数:
position:目标位置
other:源链表(转移后变空)
splice 的重要特性1. 不复制、不移动2. 迭代器仍然有效3. 转移后源节点的迭代器失效(但指向新位置)
emplace_front 详解
emplace_front 是 std::list 的成员函数,在链表头部直接构造元素。emplace_front = 在头部创建新节点(不用提前创建对象)
make_pair 详解
make_pair 是 C++ 标准库函数,用于方便地创建 pair 对象。make_pair = 自动推导类型的 pair 创建工具
std::atomic 详解
std::atomic 是 C++11 引入的原子操作模板,用于多线程编程中无需加锁就能安全地访问共享变量。
atomic = 自动保证操作的"不可分割性",多线程访问时不会出现数据竞争
emplace_back:末尾造
emplace_front:头部造
emplace:任意位置造
emplace_after:forward_list 专用,后面造
emplace_hint:关联容器,带提示造
所有 emplace:直接在容器内存里 new 对象,不拷贝、不移动、更快。
cpp
forward_list<int> flst;
auto it = flst.before_begin();
//before_begin () = 链表【第一个元素前面】的虚拟位置,它不指向任何元素,,只是给你用来在最前面插入 / 构造元素用的!
因为 C++ 有个容器叫 forward_list(单向链表),它只能往后插,不能往前插
唯一用途:专门给 insert_after / emplace_after 在头部插入元素
特点:不能用 *it 取值(它是空的);不能遍历;唯一作用:在链表最前面插入元素