C++11新特性 6.lambda表达式

目录

一.简介

1.基本概念

2.语法

二.使用示例

示例1:基础用法

示例2:带参数和返回值

示例3:捕获外部变量

示例4:修改值捕获的值(mutable 关键字)

示例5:在 STL 算法中使用(常用)

三.注意事项

四.补充


一.简介

1.基本概念

Lambda表达式是C++11引入的一种匿名函数的实现形式,能让你在代码中方便、快速地定义小型临时函数,尤其在需要简洁表达式、回调函数或函数对象时。

Lambda表达式实质上是匿名函数对象(closure)可以访问其定义时的外部作用域变量。

它弥补了传统函数指针和函数对象(functor)的不足,具有以下特点:

  • 匿名性:无需显式命名,可直接在需要的地方定义。

  • 闭包特性:可以捕获作用域内的变量,形成闭包。

  • 灵活性:支持多种捕获模式、参数传递和返回值类型。

  • 与 STL 完美结合:常用于算法(如 sortfor_each)的回调函数。

2.语法

[捕获列表] (参数列表) -> 返回类型 { 
    // 函数体 
}

(1)捕获列表(Capture List)

定义 lambda 如何访问外部变量:

  • []:不捕获任何外部变量。

  • [=]:以 值捕获 所有外部变量。

  • [&]:以 引用捕获 所有外部变量。

  • [var]:值捕获特定变量 var

  • [&var]:引用捕获特定变量 var

  • 混合捕获[=, &x](值捕获所有变量,但 x 是引用捕获)。

(2)参数列表(Parameters)

与普通函数参数类似,支持默认参数(C++14 起)。

(3)返回类型(Return Type)

  • 可省略,编译器自动推导。

  • 需显式声明时使用 ->类型。

(4)函数体(Body) 

包含实际执行的代码。

二.使用示例

示例1:基础用法

auto print = []() { 
    std::cout << "Hello Lambda!"; 
};
print(); // 输出: Hello Lambda!

示例2:带参数和返回值

auto add = [](int a, int b) -> int { //->int指定返回类型
    return a + b; 
};
std::cout << add(3, 4); // 输出: 7

示例3:捕获外部变量

int x = 10, y = 20;
auto sum = [x, &y]() { 
    return x + y; // x 是值捕获,y 是引用捕获
};
y = 30;
std::cout << sum(); // 输出: 10 + 30 = 40

捕获列表的作用是让 Lambda 表达式能够访问其定义所在作用域中的外部变量。

[x, &y]() 中,x 是通过值捕获的方式被捕获的。值捕获意味着 Lambda 表达式会在定义时复制一份 x 的值,存储在 Lambda 对象内部。此后,Lambda 表达式内部使用的 x 是这个副本,而不是原始的 x。即使在 Lambda 表达式定义之后,外部的 x 值发生了改变,Lambda 表达式内部的 x 值也不会受到影响。 

y是通过引用捕获的方式被捕获的。引用捕获意味着 Lambda 表达式内部使用的 y 是外部 y 的引用,而不是副本。因此,Lambda 表达式内部对 y 的访问和修改实际上是对外部 y 变量的访问和修改。同样,外部代码对 y 的修改也会直接影响到 Lambda 表达式内部的 y

示例4:修改值捕获的值(mutable 关键字)

#include 

int main() {
    int count = 0;
    auto increment = [count]() mutable { 
        count++; // 允许修改值捕获的变量
        return count;
    };
    int result = increment();
    std::cout << "Result of increment(): " << result << std::endl;
    std::cout << "External count: " << count << std::endl;
    return 0;
}

示例5:在 STL 算法中使用(常用)

(1)sort

#include 
#include 
#include 

int main() {
    std::vector nums = {3, 1, 4, 1, 5};
    std::sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b; // 降序排序
    });
    // 输出排序后的结果
    for (int num : nums) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}

(2 )find_if 

#include 
#include 
#include 

int main() {
    std::vector numbers = {1, 2, 3, 4, 5};
    // 使用 Lambda 表达式查找第一个大于 3 的元素
    auto it = std::find_if(numbers.begin(), numbers.end(), [](int num) { return num > 3; });
    if (it != numbers.end()) {
        std::cout << "First number greater than 3: " << *it << std::endl;
    }
    return 0;
}

 

三.注意事项

  • 生命周期问题:当使用引用捕获时,需要确保被捕获的变量在 Lambda 表达式执行时仍然有效。如果 Lambda 表达式在被捕获的变量销毁后执行,会导致未定义行为。
  • mutable 关键字:如果使用了 mutable,可以修改通过值捕获的变量,但这种修改只影响 Lambda 表达式内部的副本,不会影响外部的原始变量。
  • 性能问题:虽然 Lambda 表达式通常会被编译器内联,性能开销较小,但在某些复杂情况下,频繁创建和销毁 Lambda 对象可能会带来一定的性能损失。

 

四.补充

1. C++14:支持泛型 lambda(auto 参数)和捕获初始化:

auto lambda = [value = 42]() { return value; };

2.C++17:允许 constexpr lambda

constexpr auto square = [](int x) { return x * x; };
static_assert(square(3) == 9); // 编译期计算

3.C++20:支持模板 lambda 和 [=, this] 显式捕获。

你可能感兴趣的:(C++11新特性,c++,开发语言)