乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • C++ 学习路径
  • 第1章 C++概述与开发环境

    • C++ 语言概述与编译模型
    • 第一个 C++ 程序与规范
    • 开发环境配置
    • 预处理指令详解
  • 第2章 基本语法与类型系统

    • 变量与基本类型
    • 类型转换
    • 枚举类型
    • 引用与指针
    • 数组与 stdarray
    • 字符串与原始字符串字面量
    • const 与 constexpr
    • nullptr 与空指针
    • 类型推导 auto 与 decltype
    • 基于范围的 for 循环
    • 值类别全面解析
    • char16_t 与 char32_t
    • static_assert 编译期断言
  • 第3章 函数与重载

    • 函数声明与定义
    • 函数重载
    • 默认参数与内联函数
    • Lambda 表达式
    • 函数对象与 stdfunction
    • 后置返回类型与 noexcept
  • 第4章 类与对象

    • 类的基本定义
    • 构造函数与析构函数
    • 拷贝控制
    • 移动构造函数与移动赋值
    • 列表初始化与类内初始化器
    • 静态成员与嵌套类
    • 友元
    • =default 与 =delete
  • 第5章 继承与多态

    • 继承基础
    • 虚函数与多态
    • 虚函数表与动态绑定原理
    • 虚析构函数
    • 抽象类与纯虚函数
    • 多重继承与虚继承
    • 继承构造函数
  • 第6章 运算符重载

    • 运算符重载基础
    • 算术与关系运算符重载
    • 赋值与移动运算符重载
    • 特殊运算符重载
  • 第7章 模板与泛型编程

    • 函数模板
    • 类模板
    • 模板特化与偏特化
    • 可变参数模板
    • 别名模板与模板模板参数
    • SFINAE 与类型萃取
    • 依赖名与 typename/template 关键字
  • 第8章 异常处理

    • 异常处理机制
    • noexcept 与异常安全
    • RAII 与异常安全实践
  • 第9章 内存管理与智能指针

    • 动态内存与内存分区
    • RAII 惯用法
    • unique_ptr
    • shared_ptr 与 weak_ptr
    • 内存管理最佳实践
  • 第10章 右值引用与移动语义

    • 右值引用与值类别深度解析
    • std::move 原理与使用
    • 完美转发与 std::forward
    • 移动语义性能对比与最佳实践
  • 第11章 STL容器

    • vector 深度剖析
    • deque 内部机制
    • list 与 forward_list
    • map 与 set 深度解析
    • unordered 容器与哈希原理
    • array 与 tuple
    • 容器适配器
    • 容器选择全景指南
  • 第12章 STL算法与迭代器

    • 迭代器体系全解
    • 非变异算法
    • 变异算法
    • 排序与二分算法
    • Lambda 与算法组合
    • std::random 随机数库
    • 自定义迭代器开发
  • 第13章 IO流与文件

    • 标准 IO 流
    • 格式化输出控制
    • 文件流操作
    • 字符串流
    • std::regex 正则表达式
  • 第14章 并发与多线程

    • thread 基础与线程管理
    • mutex 与 lock_guard
    • unique_lock 与 condition_variable
    • thread_local 线程局部存储
    • atomic 与内存序
    • future 与 async 异步编程
    • std::chrono 时间库
  • 第15章 现代C++新特性

    • 从 C++11 到 C++20 演进路线
    • C++14 关键新特性
    • C++17 关键新特性
    • C++20 核心特性速览
  • 第16章 面试考点与最佳实践

    • C++ 综合最佳实践清单
    • 高频面试题精讲
    • 多线程面试题与实战
    • 内存管理常见陷阱与排查
  • 附录

    • C++ 核心知识点
    • C++ 专业术语

list 与 forward_list

定义与作用

std::list(双向链表)和 std::forward_list(单向链表,C++11)是节点式容器,元素分散存储,通过指针串联。核心优势:任意位置 O(1) 插入/删除,且不使其他迭代器失效。

#include <list>
std::list<int> lst{1, 2, 3};
lst.push_front(0);        // O(1)
lst.insert(lst.begin(), -1);  // O(1)

#include <forward_list>
std::forward_list<int> fl{1, 2, 3};
fl.push_front(0);         // O(1),只支持前端操作
特性listforward_list
节点结构双向(prev + next)单向(next only)
内存开销2 指针/节点1 指针/节点
遍历方向双向仅正向
push_backO(1)不支持(需 O(n) 找尾)
size()O(1)(C++11 起要求)不支持(设计取舍)
splice完整支持splice_after

核心原理

节点结构对比

splice 操作

完整示例

示例一:飞翔科技事件时间线

场景说明:黄俪用 list 管理飞翔科技产品迭代的事件时间线,支持在任意位置插入新事件和合并两个时间线。

#include <iostream>
#include <list>
#include <string>
#include <algorithm>

struct Event {
    std::string date;
    std::string description;

    Event(std::string d, std::string desc)
        : date(std::move(d)), description(std::move(desc)) {}
};

void printTimeline(const std::string& title, const std::list<Event>& tl) {
    std::cout << title << ":\n";
    for (const auto& e : tl)
        std::cout << "  " << e.date << " | " << e.description << "\n";
}

int main() {
    // 2026年主版本时间线
    std::list<Event> mainTimeline;
    mainTimeline.emplace_back("2026-01-15", "飞翔科技 v3.0 需求评审(孔蓝)");
    mainTimeline.emplace_back("2026-03-01", "飞翔科技 v3.0 架构设计(白歌)");
    mainTimeline.emplace_back("2026-05-20", "飞翔科技 v3.0 灰度发布");

    // 紧急修复时间线
    std::list<Event> hotfixTimeline;
    hotfixTimeline.emplace_back("2026-05-10", "紧急修复:支付回调超时(小崔)");
    hotfixTimeline.emplace_back("2026-05-12", "紧急修复:缓存击穿(白歌)");

    printTimeline("主版本时间线", mainTimeline);
    printTimeline("热修复时间线", hotfixTimeline);

    // splice:将热修复时间线合并到主时间线灰度发布之前
    auto grayPos = std::find_if(mainTimeline.begin(), mainTimeline.end(),
        [](const Event& e) { return e.description.find("灰度") != std::string::npos; });

    mainTimeline.splice(grayPos, hotfixTimeline);

    std::cout << "\n";
    printTimeline("合并后时间线", mainTimeline);
    std::cout << "热修复时间线是否为空: " << hotfixTimeline.empty() << "\n";
}

预期输出:

主版本时间线:
  2026-01-15 | 飞翔科技 v3.0 需求评审(孔蓝)
  2026-03-01 | 飞翔科技 v3.0 架构设计(白歌)
  2026-05-20 | 飞翔科技 v3.0 灰度发布
热修复时间线:
  2026-05-10 | 紧急修复:支付回调超时(小崔)
  2026-05-12 | 紧急修复:缓存击穿(白歌)

合并后时间线:
  2026-01-15 | 飞翔科技 v3.0 需求评审(孔蓝)
  2026-03-01 | 飞翔科技 v3.0 架构设计(白歌)
  2026-05-10 | 紧急修复:支付回调超时(小崔)
  2026-05-12 | 紧急修复:缓存击穿(白歌)
  2026-05-20 | 飞翔科技 v3.0 灰度发布
热修复时间线是否为空: 1

逐段分析:

  • splice 将 hotfixTimeline 的全部节点直接"挂接"到目标位置,无拷贝无移动,O(1)
  • splice 后源 list 为空,所有迭代器依然有效(指向原节点,现属于新 list)
  • 与 insert 拷贝元素相比,splice 是真正的零开销重组

示例二:forward_list 消息过滤链

场景说明:李眉用 forward_list 实现一个消息过滤链,动态插入/移除过滤器。

#include <iostream>
#include <forward_list>
#include <string>
#include <functional>

using FilterFunc = std::function<bool(const std::string&)>;

class MessageFilter {
public:
    // 在头部添加过滤器
    void prepend(FilterFunc fn) {
        filters_.push_front(std::move(fn));
    }

    // 移除特定条件过滤器
    void removeByKeyword(const std::string& keyword) {
        filters_.remove_if([&](const FilterFunc& fn) {
            // 简化为判断函数是否涉及关键词(实际应为更精确的匹配)
            return true;  // 示例:移除所有
        });
    }

    // 在某个过滤器之后插入
    template<typename Pred>
    void insertAfter(Pred pred, FilterFunc fn) {
        auto it = std::find_if(filters_.begin(), filters_.end(), pred);
        if (it != filters_.end())
            filters_.insert_after(it, std::move(fn));
    }

    bool apply(const std::string& msg) const {
        for (const auto& filter : filters_)
            if (!filter(msg)) return false;
        return true;
    }

private:
    std::forward_list<FilterFunc> filters_;
};

int main() {
    MessageFilter chain;

    // 添加过滤器
    chain.prepend([](const std::string& s) -> bool {
        return !s.empty();  // 非空检查
    });
    chain.prepend([](const std::string& s) -> bool {
        return s.size() <= 1024;  // 长度检查
    });

    std::cout << std::boolalpha;
    std::cout << "飞翔科技-日志消息: "
              << chain.apply("飞翔科技-服务器正常") << "\n";
    std::cout << "空消息: " << chain.apply("") << "\n";
}

预期输出:

飞翔科技-日志消息: true
空消息: false

逐段分析:

  • forward_list 仅支持 insert_after 和 erase_after(需要访问前驱节点)
  • 内存开销更小:每个节点仅 1 个指针(vs list 的 2 个)
  • 适合:只需正向遍历、内存敏感的简单链表场景

易错场景与面试考点

易错场景

1. forward_list 没有 size()

std::forward_list<int> fl{1, 2, 3};
// fl.size();     // ❌ 编译错误!forward_list 不提供 size()
auto n = std::distance(fl.begin(), fl.end());  // O(n)

2. list 的 sort 是成员函数

std::list<int> lst{3, 1, 2};
lst.sort();                    // ✅ 成员函数,O(n log n)
// std::sort(lst.begin(), lst.end());  // ❌ list 迭代器非随机访问

3. splice 后源 list 元素被移走

std::list<int> a{1, 2}, b{3, 4};
auto it = b.begin();
a.splice(a.end(), b);
// *it 仍然有效,但 it 现在属于 a,不属于 b

面试考点

考点要点
list vs forward_list双向 2 指针 vs 单向 1 指针
splice 复杂度O(1),仅修改指针
迭代器失效插入/删除不使其他迭代器失效
list::sort成员函数,使用归并排序
list::remove/remove_if成员函数,真正删除元素(vs 算法 remove 只是移动)
何时用 list频繁中间插入删除、需要 splice、迭代器稳定
上一页
deque 内部机制
下一页
map 与 set 深度解析