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

    • 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++ 专业术语

Lambda 与算法组合

定义与作用

Lambda 表达式是内联匿名函数对象,与 STL 算法组合使用是实现"声明式编程"的核心方式——用简短的代码描述"做什么",而非用循环描述"怎么做"。

// 传统方式:手写循环
std::vector<int> result;
for (int x : v)
    if (x > 10) result.push_back(x * 2);

// Lambda + 算法:声明式
std::vector<int> result;
std::copy_if(v.begin(), v.end(), std::back_inserter(result),
             [](int x) { return x > 10; });
std::transform(result.begin(), result.end(), result.begin(),
               [](int x) { return x * 2; });

核心原理

Lambda 编译期展开

捕获语义

完整示例

示例一:飞翔科技多维数据筛选

场景说明:高英用 Lambda + 算法组合对飞翔科技用户数据进行多条件筛选。

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>

struct User {
    std::string name;
    int age;
    double spend;      // 消费金额
    bool isVip;
    std::string city;
};

void printUsers(const std::string& title, const std::vector<User>& users) {
    std::cout << title << " (" << users.size() << " 人):\n";
    for (const auto& u : users)
        std::cout << "  " << u.name << " | " << u.age << "岁 | ¥"
                  << u.spend << " | " << (u.isVip ? "VIP" : "普通")
                  << " | " << u.city << "\n";
}

int main() {
    std::vector<User> users = {
        {"大翔", 28, 188888.8, true,  "广州"},
        {"白歌", 32, 166666.6, true,  "广州"},
        {"小崔", 25, 88888.8,  false, "深圳"},
        {"黄俪", 26, 66666.6,  false, "广州"},
        {"李眉", 35, 123456.7, true,  "广州"},
        {"孔蓝", 27, 232000.0, true,  "广州"},
        {"赵鸣", 24, 88888.8,  false, "北京"},
        {"高英", 30, 166666.6, true,  "上海"},
        {"杨英", 23, 52000.0,  false, "广州"},
        {"孙鹤", 22, 32000.0,  false, "深圳"},
    };

    // 1. copy_if:筛选 VIP 且花费大于 10 万的用户
    std::vector<User> highValueVIPs;
    std::copy_if(users.begin(), users.end(),
                 std::back_inserter(highValueVIPs),
                 [](const User& u) { return u.isVip && u.spend > 100000; });
    printUsers("=== 高价值 VIP ===", highValueVIPs);

    // 2. 链式组合:先筛广州用户、再计算总消费
    double gzTotal = 0;
    std::for_each(users.begin(), users.end(),
        [&gzTotal](const User& u) {
            if (u.city == "广州") gzTotal += u.spend;
        });
    std::cout << "\n广州地区总消费: ¥" << gzTotal << "\n";

    // 3. 值捕获 + mutable:按年龄分组统计
    int threshold = 28;
    auto youngUsers = std::count_if(users.begin(), users.end(),
        [threshold](const User& u) { return u.age < threshold; });
    std::cout << "年龄 < " << threshold << " 的用户: " << youngUsers << " 人\n";

    // 4. 引用捕获:找出非 VIP 且低消费的需关注用户
    std::vector<std::string> attentionList;
    double spendLimit = 60000;
    std::for_each(users.begin(), users.end(),
        [&attentionList, spendLimit](const User& u) {
            if (!u.isVip && u.spend < spendLimit)
                attentionList.push_back(u.name + "(" + u.city + ")");
        });

    std::cout << "\n需关注用户 (非VIP + 消费<¥" << spendLimit << "):\n";
    for (const auto& name : attentionList)
        std::cout << "  " << name << "\n";

    // 5. 泛型 Lambda (C++14):通用分组统计
    auto groupBy = [](auto& container, auto getKey) {
        std::unordered_map<
            std::decay_t<decltype(getKey(*container.begin()))>,
            int
        > groups;
        for (const auto& item : container)
            ++groups[getKey(item)];
        return groups;
    };

    auto cityGroups = groupBy(users, [](const User& u) { return u.city; });
    std::cout << "\n地区分布:\n";
    for (const auto& [city, count] : cityGroups)
        std::cout << "  " << city << ": " << count << " 人\n";
}

预期输出:

=== 高价值 VIP === (4 人):
  大翔 | 28岁 | ¥188889 | VIP | 广州
  白歌 | 32岁 | ¥166667 | VIP | 广州
  李眉 | 35岁 | ¥123457 | VIP | 广州
  孔蓝 | 27岁 | ¥232000 | VIP | 广州

广州地区总消费: ¥677000

年龄 < 28 的用户: 5 人

需关注用户 (非VIP + 消费<¥60000):
  杨英(广州)
  孙鹤(深圳)

地区分布:
  广州: 6 人
  深圳: 2 人
  北京: 1 人
  上海: 1 人

逐段分析:

  • copy_if + Lambda 替代手写 if + push_back 循环
  • for_each + 引用捕获 &gzTotal 实现累积统计
  • threshold 值捕获使 Lambda 携带外部参数
  • count_if 一步完成计数
  • C++14 泛型 Lambda(auto 参数)实现通用 groupBy 函数

示例二:Lambda 初始化捕获——资源管理

场景说明:小崔用 C++14 初始化捕获将 unique_ptr 转移到 Lambda 中。

#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>
#include <functional>

struct DatabaseConn {
    std::string dbName;
    explicit DatabaseConn(std::string name) : dbName(std::move(name)) {
        std::cout << "  连接数据库: " << dbName << "\n";
    }
    ~DatabaseConn() { std::cout << "  断开: " << dbName << "\n"; }

    std::string query(const std::string& sql) {
        return "[" + dbName + "] 结果: " + sql + " -> OK";
    }
};

int main() {
    std::cout << "=== 飞翔科技数据库查询 ===\n\n";

    // 初始化捕获:将 unique_ptr 移动到 Lambda 中
    auto conn = std::make_unique<DatabaseConn>("飞翔科技-主库");

    auto executor = [conn = std::move(conn)](const std::string& sql) {
        return conn->query(sql);
    };
    // conn 已移动,不能再使用

    // 执行多次查询
    std::vector<std::string> queries = {
        "SELECT * FROM users WHERE vip=1",
        "SELECT SUM(spend) FROM orders",
        "SELECT COUNT(*) FROM logins WHERE date='2026-06-14'",
    };

    std::cout << "执行查询:\n";
    for (const auto& q : queries)
        std::cout << "  " << executor(q) << "\n";

    // Lambda 可以传入 std::function
    std::function<std::string(const std::string&)> fn = std::move(executor);
    std::cout << "\n通过 std::function 调用:\n";
    std::cout << "  " << fn("SELECT version()") << "\n";
}

预期输出:

=== 飞翔科技数据库查询 ===

  连接数据库: 飞翔科技-主库
执行查询:
  [飞翔科技-主库] 结果: SELECT * FROM users WHERE vip=1 -> OK
  [飞翔科技-主库] 结果: SELECT SUM(spend) FROM orders -> OK
  [飞翔科技-主库] 结果: SELECT COUNT(*) FROM logins WHERE date='2026-06-14' -> OK

通过 std::function 调用:
  [飞翔科技-主库] 结果: SELECT version() -> OK
  断开: 飞翔科技-主库

逐段分析:

  • [conn = std::move(conn)]:C++14 初始化捕获,将 unique_ptr 转移到闭包
  • 移动后 Lambda 独占连接的所有权,析构时自动释放
  • std::function 可包装此 Lambda,实现在异步回调中延迟执行
  • RAII:数据库连接随 Lambda 生命周期管理,无需手动关闭

易错场景与面试考点

易错场景

1. 引用捕获 + 悬垂引用

auto makeLambda() {
    int x = 42;
    return [&x]() { return x; };  // ❌ x 在函数返回后销毁
}

2. for_each 中修改容器结构

std::vector<int> v{1, 2, 3};
// std::for_each(v.begin(), v.end(), [&](int x) {
//     if (x == 2) v.push_back(4);  // ❌ 迭代器可能失效
// });

3. 捕获 this 后对象被销毁

struct Widget {
    void schedule() {
        // ❌ 如果 this 在回调执行前销毁 → 悬垂
        asyncCall([this]() { this->doWork(); });
    }
};

面试考点

考点要点
值捕获 vs 引用捕获值捕获安全但不可变,引用捕获注意生命周期
mutable 关键字允许修改值捕获的副本
泛型 LambdaC++14 auto 参数,等价于模板化的 operator()
初始化捕获C++14 [x = expr],支持 move-only 类型
与 std::function 配合Lambda 可转为 std::function,有虚函数调用开销
闭包类型每个 Lambda 表达式有唯一匿名类型,即使签名相同
捕获时机值捕获在 Lambda 定义时发生,非调用时
上一页
排序与二分算法
下一页
std::random 随机数库