C++ Lambda 表达式中的参数引用
Lambda 表达式是 C++11 引入的强大特性,它允许我们定义匿名函数对象。在 lambda 表达式中,参数的引用方式与普通函数类似,但有一些额外的捕获机制需要注意。
1. Lambda 表达式的基本语法
[capture](parameters) -> return_type {
// 函数体
}
2. 参数传递方式
值传递参数
auto lambda = [](int x, int y) {
return x + y;
};
int result = lambda(3, 4); // result = 7
引用传递参数
auto modifyValue = [](int& x) {
x *= 2;
};
int value = 5;
modifyValue(value); // value 现在为 10
const 引用传递参数
auto printLargeObject = [](const std::vector<int>& vec) {
for (const auto& item : vec) {
std::cout << item << " ";
}
std::cout << std::endl;
};
std::vector<int> numbers = {1, 2, 3, 4, 5};
printLargeObject(numbers); // 不会复制整个vector
3. 捕获列表中的引用
Lambda 表达式可以通过捕获列表捕获外部变量,这是与普通函数不同的地方:
按值捕获
int x = 10;
auto lambda = [x]() { // 按值捕获x
std::cout << x << std::endl;
// x++; // 错误:按值捕获的变量默认是const的
};
lambda(); // 输出 10
按引用捕获
int x = 10;
auto lambda = [&x]() { // 按引用捕获x
std::cout << x << std::endl;
x++; // 可以修改,会影响外部变量
};
lambda(); // 输出 10
std::cout << x << std::endl; // 输出 11
使用 mutable 关键字
int x = 10;
auto lambda = [x]() mutable { // 按值捕获,但允许修改副本
std::cout << x << std::endl;
x++; // 修改的是副本,不影响外部变量
std::cout << x << std::endl;
};
lambda(); // 输出 10, 然后 11
std::cout << x << std::endl; // 输出 10(外部变量未改变)
4. 通用引用和完美转发
C++14 引入了初始化捕获,可以更灵活地处理参数:
// C++14 通用 lambda
auto lambda = [](auto&& x) {
return std::forward<decltype(x)>(x);
};
int a = 5;
const int b = 10;
auto result1 = lambda(a); // 传递左值
auto result2 = lambda(42); // 传递右值
auto result3 = lambda(b); // 传递const左值
5. 捕获 this 指针
在类成员函数中,lambda 可以捕获 this 指针来访问类成员:
class MyClass {
public:
int value = 42;
void printValue() {
auto lambda = [this]() {
std::cout << value << std::endl; // 通过this访问成员
};
lambda();
}
};
6. 默认捕获模式
int x = 10, y = 20;
// 默认按值捕获所有外部变量
auto lambda1 = [=]() {
std::cout << x + y << std::endl;
};
// 默认按引用捕获所有外部变量
auto lambda2 = [&]() {
x++; y++;
std::cout << x + y << std::endl;
};
// 混合捕获:x按值,其余按引用
auto lambda3 = [=, &y]() {
// x是按值捕获,不能修改
y++; // y是按引用捕获,可以修改
std::cout << x + y << std::endl;
};
// 混合捕获:y按引用,其余按值
auto lambda4 = [&, x]() {
// x是按值捕获,不能修改
y++; // y是按引用捕获,可以修改
std::cout << x + y << std::endl;
};
7. 实际应用示例
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
int threshold = 3;
// 使用lambda作为谓词,捕获外部变量threshold
auto it = std::find_if(numbers.begin(), numbers.end(),
[threshold](int value) {
return value > threshold;
});
if (it != numbers.end()) {
std::cout << "First value greater than " << threshold
<< " is " << *it << std::endl;
}
// 修改vector中的元素
std::for_each(numbers.begin(), numbers.end(),
[](int& value) { // 参数为引用,可以修改元素
value *= 2;
});
// 输出结果
for (const auto& num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
注意事项
- 生命周期问题:按引用捕获变量时,要确保lambda被执行时,被捕获的变量仍然存在
- 悬空引用:如果捕获的引用指向的对象已被销毁,会导致未定义行为
- 默认捕获的风险:使用
[&]或[=]可能会意外捕获不需要的变量 - mutable 的使用:只有需要修改按值捕获的变量时才使用mutable关键字
Lambda 表达式中的参数引用机制非常灵活,正确使用可以编写出简洁高效的代码,但需要注意避免常见的陷阱。

浙公网安备 33010602011771号