深入理解 C++ Lambda 表达式:从基础到实战
Lambda 表达式是 C++11 及后续标准引入的重要特性,它允许我们定义匿名函数,极大地提升了代码的简洁性和灵活性。本文将结合实战代码,从基础语法、捕获方式、mutable 关键字、结合 STL / 智能指针使用等维度,全面解析 Lambda 表达式的核心知识点。
一、Lambda 表达式基础语法
Lambda 表达式的核心语法结构如下:
[capture](parameters) mutable -> return_type { function_body }
- 捕获子句(capture):指定外部变量如何被 Lambda 访问(值捕获、引用捕获等);
- 参数列表(parameters):与普通函数参数列表一致,C++14 支持自动类型推导(auto);
- mutable:可选,移除 Lambda 体内变量的 const 限制(仅对值捕获生效);
- 返回类型(return_type):可选,编译器可自动推导;
- 函数体(function_body):Lambda 的执行逻辑。
最简示例
#include<iostream>
using namespace std;
int main() {
// 无捕获、无参数、返回值自动推导
auto add = [](int a, int b) { return a + b; };
cout << "10 + 20 = " << add(10, 20) << endl; // 输出30
// C++14自动类型推导参数
auto print = [](auto x) { cout << "值:" << x << endl; };
print(123); // 输出整数
print(3.14); // 输出浮点数
return 0;
}
二、Lambda 的变量捕获规则
捕获子句是 Lambda 的核心,决定了如何访问外部作用域的变量,主要分为以下几种:
1. 值捕获([=] 或 显式指定变量)
值捕获会拷贝外部变量到 Lambda 内部,默认情况下 Lambda 体内的拷贝变量是const的(不可修改)。
#include<iostream>
using namespace std;
class Int {
private:
int value;
public:
Int(int x = 0) : value(x) {}
void Print() const { cout << "value: " << value << endl; }
int& Value() { return value; }
};
void func(int a) {
Int it(a);
// [=] 捕获所有外部变量(值拷贝),mutable 解除const限制
auto lambda = [=](int x) mutable -> void {
it.Value() = 100; // 需mutable才能修改拷贝的变量
it.Print(); // 输出value: 100
a = 200; // 修改的是拷贝的a,不影响外部
cout << "内部a: " << a << endl; // 输出200
};
lambda(0);
cout << "外部a: " << a << endl; // 输出原始值(未被修改)
}
int main() {
func(10);
return 0;
}
注意:值捕获的变量是 Lambda 创建时的拷贝,而非执行时的最新值。
2. 引用捕获([&] 或 显式指定变量)
引用捕获直接访问外部变量的内存地址,修改会影响原变量,无需 mutable 即可修改。
#include<iostream>
using namespace std;
class Int {
private:
int value;
public:
Int(int x = 0) : value(x) {}
void Print() const { cout << "value: " << value << endl; }
void setValue(int x) { value = x; }
};
int main() {
Int a(10);
a.Print(); // 输出value: 10
// [&] 引用捕获所有外部变量
auto lambda = [&]() { a.setValue(100); };
lambda();
a.Print(); // 输出value: 100(原变量被修改)
return 0;
}
3. 混合捕获
可混合使用值捕获和引用捕获,显式指定部分变量的捕获方式:
void func(int a, int b) {
Int ita(a), itb(b);
// 引用捕获ita,值捕获其他所有变量
auto lambda = [=, &ita]() -> void {
ita.setValue(100); // 引用捕获,修改原变量
itb.Print(); // 值捕获,访问拷贝的itb
cout << a << endl; // 值捕获,访问拷贝的a
};
lambda();
}
4. this 捕获(类成员函数中)
在类的成员函数中,[this] 可捕获当前对象的 this 指针,从而访问类的成员变量 / 成员函数:
#include<iostream>
using namespace std;
class Int {
private:
int value;
static int num;
public:
Int(int x = 0) : value(x) {}
void func() {
// 捕获this指针,访问成员变量和静态成员
auto lambda = [this]() -> void {
value = 1000; // 等价于this->value
num += 100; // 静态成员可直接访问
cout << value << endl; // 输出1000
cout << num << endl; // 输出100
};
lambda();
}
void Print() const { cout << "value: " << value << endl; }
};
int Int::num = 0;
int main() {
Int a(10);
a.func();
a.Print(); // 输出value: 1000
return 0;
}
三、Lambda 结合智能指针使用
Lambda 表达式常与智能指针(如shared_ptr)结合,需注意捕获方式对引用计数的影响:
#include<iostream>
#include<memory>
using namespace std;
class Int {
private:
int value;
public:
Int(int x = 0) : value(x) {
cout << "创建对象:" << value << endl;
}
~Int() {
cout << "销毁对象:" << value << endl;
}
void Print() const { cout << "value: " << value << endl; }
int& Value() { return value; }
};
int main() {
shared_ptr<Int> pa(new Int(10));
cout << "初始引用计数:" << pa.use_count() << endl; // 输出1
// 值捕获shared_ptr,引用计数+1
auto lambda = [pa]() -> void {
pa->Print(); // 输出value: 10
pa->Value() = 100;
pa->Print(); // 输出value: 100
cout << "Lambda内引用计数:" << pa.use_count() << endl; // 输出2
};
lambda();
pa->Print(); // 输出value: 100(原对象被修改)
cout << "Lambda执行后引用计数:" << pa.use_count() << endl; // 输出1
return 0;
}
说明:值捕获shared_ptr会增加引用计数,确保 Lambda 执行期间对象不会被销毁;执行完毕后 Lambda 销毁,引用计数减 1。
四、Lambda 的实战场景:线程同步(条件变量)
Lambda 表达式可简化条件变量的谓词判断,让代码更简洁:
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;
const int n = 10;
int tag = 0;
mutex mtx;
condition_variable cond;
// 线程1:输出偶数
void funa() {
unique_lock<mutex> locker(mtx);
for (int i = 0; i <= n; ++i) {
// Lambda作为谓词,判断tag是否为偶数
cond.wait(locker, []() -> bool { return tag % 2 == 0; });
if (tag <= n) {
printf("funa: %d\n", tag);
}
tag += 1;
cond.notify_all(); // 唤醒其他线程
}
}
// 线程2:输出奇数
void funb() {
unique_lock<mutex> locker(mtx);
for (int i = 0; i <= n; ++i) {
cond.wait(locker, []() -> bool { return tag % 2 == 1; });
if (tag <= n) {
printf("funb: %d\n", tag);
}
tag += 1;
cond.notify_all();
}
}
int main() {
thread tha(funa);
thread thb(funb);
tha.join();
thb.join();
return 0;
}
上述代码通过 Lambda 作为condition_variable::wait的谓词,替代了传统的 while 循环判断,代码更简洁易读。
五、Lambda 表达式的核心总结
- 匿名性:Lambda 是匿名函数,可通过 auto 接收其类型,直接调用或作为参数传递;
- 捕获规则:
[]:无捕获;[=]:值捕获所有外部变量;[&]:引用捕获所有外部变量;[var]:值捕获指定变量 var;[&var]:引用捕获指定变量 var;[this]:类成员函数中捕获 this 指针;
- mutable:仅对值捕获生效,解除 Lambda 体内拷贝变量的 const 限制;
- 灵活性:C++14 支持自动类型推导参数,可适配不同类型的输入;
- 生命周期:值捕获的变量是拷贝,引用捕获需注意外部变量的生命周期(避免悬空引用)。
Lambda 表达式是现代 C++ 的核心特性之一,熟练掌握其用法可大幅提升代码的简洁性和可读性,尤其在 STL 算法、线程编程、回调函数等场景中应用广泛。希望本文的实战案例能帮助大家深入理解 Lambda 的本质和用法。
更多推荐


所有评论(0)