用Python和Matplotlib可视化理解:为什么梯度向量就是曲面的法线方向?
2026/5/8 21:34:15
目录
定义
语法结构
常见捕获列表
常见使用场景
Lambda的本质
Lambda的发展和问题
C++中的Lambda表达式是C++11引入的新特性,允许在代码中定义匿名函数。简单而言,他就是一个匿名函数对象,通常用于简单、不需要复用、或者需要访问当前上下文变量的场景。
Lambda表达式完整语法如下:
[捕获列表](参数类型) mutable 异常属性 -> 返回类型 {函数体}大部分情况下,都会是[捕获列表] (mutable根据需要)(参数类型){函数体}的形式,异常属性和-> 返回类型都是省略不写的。
| 写法 | 含义 |
[] | 不捕获任何外部变量。 |
[=] | 值捕获所有外部变量(Lambda 内持有的是副本,只读)。 |
[&] | 引用捕获所有外部变量(Lambda 内操作的是本体,可读写)。 |
[x] | 只值捕获变量x,不捕获其他。 |
[&x] | 只引用捕获变量x,不捕获其他。 |
[=, &y] | 默认值捕获所有,但变量y引用捕获。 |
[&, x] | 默认引用捕获所有,但变量x值捕获。 |
[this] | 捕获当前类的this指针(让 Lambda 能访问类的成员变量/函数)。 |
1.场景一:配合STL一起使用。
#include<vector> #include <iostream> int main() { std::vector<int> v = {4, 3, 2, 1, 5}; std::sort(v.begin(), v.end()); //默认情况下是从小到大排序 for (int i : v) { std::cout << i << " "; } std::cout << std::endl; //使用Lambda表达式进行自定义排序 std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; // 从大到小排序 }); for (int i : v) { std::cout << i << " "; } std::cout << std::endl; return 0; }2.场景二:捕获外部变量同时不想传一堆参数时。
#include<vector> #include <iostream> int main() { std::vector<int> v = {4, 3, 2, 1, 5}; std::sort(v.begin(), v.end()); int value = 2; //通过Lambda找出第一个大于2的元素 auto it = std::find_if(v.begin(), v.end(), [value](int x) { return x > value; }); if (it != v.end()) { std::cout << "First number > " << value << " is " << *it << std::endl; } return 0; }3.场景三:mutable关键字的使用。
#include <iostream> int main() { int x = 5; // 按值捕获 x。如果没有 mutable, x++ 会报错 auto f = [x]() mutable { x++; std::cout << "x Value: " << x << std::endl; }; f(); f(); std::cout << "Outside: " << x << std::endl; // 输出 Outside: 5 (外部变量未变) return 0; }在C++编译器眼中,Lambda表达式本质是一个匿名的“仿函数”对象。
例如当写下以下代码时,
int a = 10; auto f = [a](int x) { return a + x; };编译器会自动生成匿名类,类似于:
class __AnonymousLambda { private: int m_a; // 对应捕获列表 [a] public: __AnonymousLambda(int a) : m_a(a) {} // 构造函数 // 对应函数体,参数列表 int operator()(int x) const { return m_a + x; } };这就是为什么Lambda可以拥有状态,也可以当作参数传递。
C++14增强了Lambda表达式,允许在参数列表中使用auto,使得lambda更加灵活,类似于模版函数,如下所示:
auto add = [](auto x, auto y) { return x + y; } std::cout << add(1, 2) << std::endl; // int相加,输出 3 std::cout << add(1.5, 2.5) << std::endl; // double相加,输出 4.0 std::cout << add(std::string("Hi "), "C++"); // string相加同时,在使用Lambda时,要注意可能出现的问题,Lambda的生命周期。
当使用了引用捕获,而Lambda的生命周期长于被捕获变量的生命周期(比如在一个函数中返回了一个 Lambda,该 Lambda 引用了函数内的局部变量),这会导致悬垂引用,进而引发程序崩溃。
错误实例如下:
std::function<void()> getPrinter() { int value = 42; // 错误!引用捕获了局部变量 value // 当 getPrinter 返回时,value 被销毁,Lambda 内部持有了无效引用 return [&]() { std::cout << value << std::endl; }; }这种情况下,将引用捕获[&]改成值捕获[=]或者[value]即可。