C++ 的lambda

十二月 20, 2023 [c++, lambda] #c++

C++ 的lambda

lambda原型如下:

captures mutable exception attribute {body} 其中,

captures是在lambda函数体中可以访问的外部变量,有两种默认捕获模式:按值捕获和按引用捕获 params指定表达式的参数 mutable修饰符表示lambda函数可以修改捕获的变量,并调用对象的非const方法 exception告诉编译器函数是否抛异常(noexcept) attribute用来声明属性 lambda的返回值:如果函数中有return语句,则类型从return后面的表达式推导而来;如果没有return语句,则类似于void。

关于capture的捕获模式: [a, &b] 表示a按值捕获,b按引用捕获;[]表示不捕获任何外部变量

lambda有哪些用法?

STL中 if类函数族,比如

std::find_if(container.begin(), container.end(), [](int val){ return val>0})

自定义比较函数(std::sort, std::nthelement, std::lower_bound) 为std::unique_ptr, std::shared_ptr自定义解析器

用lambda实现闭包

lambda与闭包 闭包是lambda表达式的运行期对象,根据不同的捕获模式,闭包会持有数据的副本或引用。在上面find_if函数中,闭包就是作为第三个实参在运行期传递给find_if函数的。 闭包类就是实例化闭包的类。每个lambda表达式都会触发编译器生成独一无二的闭包类。而闭包中的语句会变成它的闭包类成员函数的可执行指令。 就存在期而言,lambda和闭包类存在于编译期,闭包存在于运行期。 闭包属于可调用对象,因此可以像变量一样对它赋值。

int target = 10;
auto biger10 = [](int i){ return i>target;};
int testvar = 100;
biger10(testvar);

引用悬挂问题

默认按引用捕获的一个可能问题是, 引用悬挂。即按引用捕获会导致包含指向局部变量的引用,当lambda离开局部作用域时,会导致引用的那个变量被释放,lambda里的那个引用发生"悬挂"。

 using func_v = std::vector<std::function<bool(int)>>;
 
 func_v filters;
 ...
 void addFilters()
 {
   int threshold = 5; // 局部变量
   filters.emplace_back([&threshold](int v){return v<threshold;});    
 }// threshold已经被销毁,但是filters中仍保留着对它的引用
 filters.doSomething();  // 未定义行为

广义lambda捕获,也称为 init capture

由于C ++ 11仅具有按值和按引用捕获,因此缺少了按移动捕获。 C ++ 14引入了广义lambda捕获,也称为 init capture 。 它允许您指定从lambda生成的闭包类中的数据成员的名称, 以及初始化该数据成员的表达式。

auto pw = std::make_unique<Widget>(); 

// configure *pw

auto func = [pWidget = std::move(pw)] { 
return pWidget->isValidated() && pWidget->isArchived(); 
};

C++11中 请注意,lambda的参数是一个左值引用(因为绑定对象中移动的pw是一个左值)并且有一个const限定符(用于模拟lambda的constness;所以如果原始lambda被声明为可变的,不会使用const限定符。

auto pw = std::make_unique<Widget>();
// configure *pw;

auto func = std::bind( [](const std::unique_ptr<Widget>& pWidget)
    { return pWidget->isValidated() && pWidget->isArchived(); },
    std::move(pw) );

其他

最后,this 指针只能按值捕获 [this] ,不能按引用捕获 [&this] 。 https://zhuanlan.zhihu.com/p/150554945