C++ -- lambda捕获

C++ Lambda 捕获分为‌基础捕获 ‌、‌混合捕获 ‌、‌特殊捕获 ‌和‌C++14/20 新特性‌。

1. 基础捕获:值 vs 引用

A. 空捕获 []

不访问任何外部变量。

cpp 复制代码
int x = 10;
auto f = ‌:ml-search[] { 
    // std::cout << x; // 错误!x 未捕获
    return 42; 
};
B. 按值捕获 [x]

拷贝外部变量。‌内部修改不影响外部 ‌,且默认不可修改(除非加 mutable)。

cpp 复制代码
int x = 10;
auto f = ‌:ml-search[x] { 
    // x = 20; // 错误!按值捕获的变量是 const 的
    return x; 
};
// x 仍然是 10
C. 按值捕获 + mutable [x] mutable

允许修改‌副本 ‌,但‌不影响外部变量‌。

cpp 复制代码
int x = 10;
auto f = ‌:ml-search[x] mutable { 
    x = 20; // 合法,修改的是内部副本
    return x; 
};
std::cout << f() << std::endl; // 输出 20
std::cout << x << std::endl;   // 输出 10 (外部未变)
D. 按引用捕获 [&x]

直接引用外部变量。‌内部修改直接影响外部‌。需注意生命周期(悬空引用风险)。

cpp 复制代码
int x = 10;
auto f = ‌:ml-search[&x] { 
    x = 20; // 合法,直接修改外部 x
    return x; 
};
f();
std::cout << x << std::endl; // 输出 20 (外部已变)

2. 默认捕获与混合捕获(最常用)

E. 默认按值捕获 [=]

Lambda 体内用到的所有局部变量都按值拷贝。

cpp 复制代码
int a = 1, b = 2;
auto f = ‌:ml-search[=] { 
    return a + b; 
};

注意:在 C++11/14 中,[=] 也会隐式捕获 this 指针(如果使用了成员变量)。

F. 默认按引用捕获 [&]

Lambda 体内用到的所有局部变量都按引用绑定。

cpp 复制代码
int a = 1, b = 2;
auto f = ‌:ml-search[&] { 
    a++; b++; // 直接修改外部变量
};
G. 混合捕获:默认值 + 特定引用 [=, &x]

场景‌:大部分变量只需读取(拷贝开销小或需要快照),但某个大对象或需要修改的变量使用引用。

cpp 复制代码
int a = 1;
std::vector<int> huge_vec(1000000); // 大对象
auto f = ‌:ml-search[=, &huge_vec] { 
    // a 是拷贝(安全,快照)
    // huge_vec 是引用(避免拷贝百万级数据,且可修改)
    huge_vec.push_back(a); 
};
H. 混合捕获:默认引用 + 特定值 [&, x]

场景‌:大部分变量需要修改外部状态,但某个变量(如 ID、配置)需要保留创建时的副本,防止外部意外修改。

cpp 复制代码
int id = 100;
int status = 0;
auto f = ‌:ml-search[&, id] { 
    status = 1; // 修改外部 status
    // id = 200; // 错误!id 是 const 副本
    std::cout << "ID at creation: " << id << std::endl;
};
id = 999; // 外部修改 id
f();      // 输出: ID at creation: 100 (内部仍保留旧值)

3. 类成员与 this 指针

I. 捕获 this [this]

在类成员函数中,若要访问成员变量,必须捕获 this

cpp 复制代码
class MyClass {
    int val = 10;
public:
    void doWork() {
        // auto f = ‌:ml-search[val] {}; // 错误!C++11/14/17 不能直接捕获成员变量
        auto f = ‌:ml-search[this] { 
            val = 20; // 通过 this->val 访问
        };
        f();
    }
};

风险:如果 MyClass 对象销毁了,但 Lambda 还被持有(例如在线程池中),调用 Lambda 会导致 Crash。

J. C++20 新特性:按值捕获 *this [*this]

解决上述风险‌。它会拷贝整个对象到 Lambda 内部。

cpp 复制代码
// C++20
auto f = ‌:ml-search[*this] { 
    val = 20; // 修改的是 Lambda 内部拷贝的对象,不影响原对象
};

优点:安全,无悬空指针。缺点:如果对象很大,拷贝开销大。

4. C++14 初始化捕获(Init Capture / Generalized Capture)

这是 C++14 引入的强大功能,允许在捕获列表中‌定义新变量‌并初始化。它解决了"移动语义"和"重命名"的问题。

K. 移动捕获(Move Capture)

用于捕获不可拷贝的对象(如 std::unique_ptr)。

cpp 复制代码
auto ptr = std::make_unique<int>(100);
// auto f = ‌:ml-search[ptr] {}; // 错误!unique_ptr 不可拷贝
auto f = ‌:ml-search[p = std::move(ptr)] { 
    std::cout << *p << std::endl; 
};
// ptr 现在为空,所有权已转移给 Lambda 内部的 p
L. 捕获表达式结果

可以捕获任意表达式的结果,甚至给变量起别名。

cpp 复制代码
int x = 10;
// 捕获 x 的两倍,并存入名为 doubled_x 的新变量
auto f = ‌:ml-search[doubled_x = x * 2] { 
    return doubled_x; 
};
M. 捕获引用(C++14)

虽然 C++11 有 [&x],但 C++14 允许更灵活的引用初始化。

cpp 复制代码
int x = 10;
auto f = ‌:ml-search[&ref_x = x] { 
    ref_x = 20; 
};
相关推荐
凡人叶枫1 小时前
Effective C++ 条款04:确定对象被使用前已先被初始化
java·linux·开发语言·c++·嵌入式开发
不想写代码的星星2 小时前
std::move 根本不移动,就像老婆饼里没有老婆
c++
redaijufeng2 小时前
C++雾中风景7:闭包
c++·算法·风景
小欣加油2 小时前
leetcode287寻找重复数
数据结构·c++·算法·leetcode
思麟呀2 小时前
C++11 核心特性(三):强类型枚举、static_assert 与 std::tuple
开发语言·c++
一拳一个呆瓜3 小时前
【STL】C++程序的启动与终止
c++·stl
凡人叶枫3 小时前
Effective C++ 条款07:为多态基类声明 virtual 析构函数
linux·c语言·开发语言·c++
凡人叶枫3 小时前
Effective C++ 条款10:令 operator= 返回一个 reference to *this
java·linux·服务器·开发语言·c++·effective c++
王老师青少年编程3 小时前
2026年全国青少年信息素养大赛算法应用主题赛(C++赛项-复赛模拟卷6:文末附答案)
c++·答案·模拟卷·复赛·2026年·青少年信息素养大赛·算法应用主题赛
视觉小萌新4 小时前
C++利用libmicrohttpd制作交互网页端——C1
java·c++·交互