Lambda 表达式概述
Lambda表达式是C++11引入的重要特性,它允许在代码中定义匿名函数对象。Lambda特别适用于需要传递少量代码作为参数的场景,比如STL算法、回调函数和异步操作。
基本语法结构
Lambda表达式的基本语法如下:
cpp
[capture-list] (parameters) mutable -> return-type { function-body }
捕获列表详解
捕获列表定义了Lambda如何访问外部变量:
cpp
// 不捕获任何变量 auto func1 = [] { return 42; }; // 值捕获 int x = 10; auto func2 = [x] { return x + 5; }; // 引用捕获 auto func3 = [&x] { x += 5; }; // 混合捕获 int y = 20, z = 30; auto func4 = [x, &y, &z] { y = x + z; }; // 默认值捕获 auto func5 = [=] { return x + y; }; // 默认引用捕获 auto func6 = [&] { x++; y++; };
参数列表和返回类型
cpp
// 无参数 auto simple = [] { return 42; }; // 带参数 auto add = [](int a, int b) { return a + b; }; // 显式指定返回类型 auto divide = [](double a, double b) -> double { if (b == 0.0) return 0.0; return a / b; }; // C++14 支持auto参数 auto generic_add = [](auto a, auto b) { return a + b; };
mutable 关键字
cpp
int counter = 0; // 错误:不能修改值捕获的变量 // auto increment = [counter] { counter++; }; // 正确:使用mutable auto increment = [counter]() mutable { counter++; return counter; };
捕获机制详解
值捕获 vs 引用捕获
cpp
void demonstrate_capture() { int value = 10; int ref_value = 20; // 值捕获 auto value_capture = [value]() { std::cout << "值捕获: " << value << std::endl; // value++; // 错误:不能修改值捕获的变量 }; // 引用捕获 auto ref_capture = [&ref_value]() { ref_value++; // 可以修改原变量 std::cout << "引用捕获: " << ref_value << std::endl; }; value = 100; ref_value = 200; value_capture(); // 输出: 值捕获: 10 ref_capture(); // 输出: 引用捕获: 201 }
初始化捕获 (C++14)
cpp
void init_capture() { int x = 10; // C++14 初始化捕获 auto lambda = [y = x + 5]() { return y * 2; }; std::cout << lambda() << std::endl; // 输出 30 // 移动语义捕获 std::unique_ptr<int> ptr = std::make_unique<int>(42); auto move_lambda = [captured_ptr = std::move(ptr)]() { return *captured_ptr; }; }
实际应用示例
STL 算法中的应用
cpp
void stl_examples() { std::vector<int> numbers = {5, 2, 8, 1, 9, 3}; // 排序 std::sort(numbers.begin(), numbers.end(), [](int a, int b) { return a > b; }); // 查找 auto it = std::find_if(numbers.begin(), numbers.end(), [](int n) { return n % 2 == 0; }); // 遍历 std::for_each(numbers.begin(), numbers.end(), [](int n) { std::cout << n << " "; }); // 转换 std::vector<int> squared; std::transform(numbers.begin(), numbers.end(), std::back_inserter(squared), [](int n) { return n * n; }); }
多线程编程
cpp
void thread_example() { std::vector<std::thread> threads; std::mutex mtx; int shared_counter = 0; for (int i = 0; i < 10; ++i) { threads.emplace_back([&, i]() { std::lock_guard<std::mutex> lock(mtx); shared_counter += i; std::cout << "线程 " << i << " 完成" << std::endl; }); } for (auto& t : threads) { t.join(); } std::cout << "最终计数: " << shared_counter << std::endl; }
回调函数和事件处理
cpp
class EventHandler { std::vector<std::function<void(int)>> callbacks; public: void register_callback(std::function<void(int)> callback) { callbacks.push_back(callback); } void trigger_event(int value) { for (auto& cb : callbacks) { cb(value); } } }; void callback_example() { EventHandler handler; int external_state = 0; // 注册Lambda回调 handler.register_callback([&external_state](int value) { external_state = value * 2; std::cout << "回调执行: " << external_state << std::endl; }); handler.trigger_event(42); }
高级特性
递归Lambda
cpp
void recursive_example() { // 使用std::function实现递归 std::function<int(int)> factorial = [&](int n) -> int { return n <= 1 ? 1 : n * factorial(n - 1); }; std::cout << "5! = " << factorial(5) << std::endl; // 使用Y组合子 auto y_combinator = [](auto f) { return [f](auto... args) { return f(f, args...); }; }; auto fact = y_combinator([](auto self, int n) -> int { return n <= 1 ? 1 : n * self(self, n - 1); }); std::cout << "6! = " << fact(6) << std::endl; }
constexpr Lambda (C++17)
cpp
constexpr auto compile_time_lambda = [](int n) { return n * n; }; void constexpr_example() { constexpr int result = compile_time_lambda(5); static_assert(result == 25, "编译时计算"); std::array<int, compile_time_lambda(3)> arr; std::cout << "数组大小: " << arr.size() << std::endl; }
最佳实践和注意事项
生命周期管理
cpp
std::function<void()> create_lambda() { int local_var = 42; // 危险:捕获了局部变量的引用 // return [&local_var]() { std::cout << local_var; }; // 安全:值捕获 return [local_var]() { std::cout << local_var; }; // 或者使用shared_ptr auto shared_data = std::make_shared<int>(42); return [shared_data]() { std::cout << *shared_data; }; }
性能考虑
cpp
void performance_considerations() { // 小Lambda通常会被内联 std::vector<int> data = {1, 2, 3, 4, 5}; std::sort(data.begin(), data.end(), [](int a, int b) { return a < b; // 这个Lambda很可能会被内联 }); // 大的复杂Lambda可能不会被内联 auto complex_operation = [](const auto& container) { // 复杂操作... return std::accumulate(container.begin(), container.end(), 0); }; }
类型推导和auto
cpp
void type_deduction() { // auto 推导Lambda类型 auto simple = [](int x) { return x * 2; }; // std::function 类型擦除 std::function<int(int)> func = simple; // 使用decltype获取Lambda类型 using LambdaType = decltype(simple); // 模板函数中的Lambda template<typename F> void process_data(F func) { // 使用func... } process_data([](int x) { return x + 1; }); }
常见陷阱和解决方案
悬挂引用问题
cpp
void dangling_reference() { std::function<void()> callback; { int temp = 100; callback = [&temp]() { std::cout << temp; // 危险:temp可能已被销毁 }; } // callback(); // 未定义行为 // 解决方案:值捕获或shared_ptr int safe_value = 100; callback = [safe_value]() { std::cout << safe_value; // 安全 }; callback(); // 安全 }
mutable 的正确使用
cpp
void mutable_usage() { int count = 0; // 错误用法 auto wrong = [count]() mutable { count++; std::cout << count; }; wrong(); // 输出1 wrong(); // 输出2,但原count仍然是0 // 正确用法:如果需要修改外部变量,使用引用捕获 auto correct = [&count]() { count++; std::cout << count; }; correct(); // count变为1 correct(); // count变为2 }
总结
C++ Lambda表达式是现代C++编程中不可或缺的工具,它提供了简洁、灵活的匿名函数定义方式。通过合理使用捕获列表、参数列表和返回类型,可以创建各种功能强大的Lambda表达式。
关键要点:
根据需求选择合适的捕获方式(值捕获/引用捕获)
注意变量的生命周期,避免悬挂引用
在STL算法和多线程编程中充分利用Lambda
使用mutable时要理解其实际作用
考虑性能影响,小Lambda通常会被优化内联