C++ lambda的几个坑
- 捕获列表的生命周期问题:
#include <iostream>
#include <functional>
using namespace std;
function<int()> make_lambda() {
int x = 42;
function<int()> lambda = [x]() -> int {
return x;
};
return lambda;
}
int main() {
function<int()> lambda = make_lambda();
cout << lambda() << endl; // 输出结果为42
// 直接释放x,此时lambda中存储了x的引用
int x = 0;
lambda = [x]() -> int {
return x;
};
cout << lambda() << endl; // 输出结果为随机值(悬垂指针)
return 0;
}
在上述代码中,make_lambda()函数返回一个使用值捕获的lambda表达式,其中捕获了一个整数变量x。但是当lambda表达式被存储之后,x所在的栈帧就已经被销毁了,此时如果直接释放x,则lambda表达式中存储的是一个指向无效内存地址的引用,会导致悬垂指针的问题。
- mutable关键字的使用:
#include <iostream>
#include <functional>
using namespace std;
void modify_lambda() {
int x = 42;
function<int()> lambda = [=]() mutable -> int {
x++;
return x;
};
cout << lambda() << endl; // 输出结果为43
cout << lambda() << endl; // 输出结果为44
}
int main() {
modify_lambda();
int x = 42;
function<int()> lambda = [&x]() mutable -> int {
x++;
return x;
};
cout << lambda() << endl; // 输出结果为43
cout << x << endl; // 输出结果为42
return 0;
}
在上述代码中,modify_lambda()函数演示了在使用值捕获的lambda表达式中添加mutable关键字,并尝试修改被捕获的变量x。注意,由于使用了mutable,因此x的值可以被修改,结果为输出44而不是42。但是这也意味着整个程序中存在两个同名的变量x,因此在使用引用捕获的lambda表达式中修改x的值时,实际上并没有修改到外部的变量x,导致程序的行为与预期不一致。
- 参数类型的推导:
#include <iostream>
#include <functional>
using namespace std;
void print_lambda(function<void(int)> lambda) {
lambda(10);
}
int main() {
// 下面这行代码会导致编译错误
// 因为编译器无法确定lambda表达式中使用的参数类型
// print_lambda([](x) { cout << x << endl; });
// 应该利用auto关键字或显式指定参数类型
print_lambda([](int x) { cout << x << endl; });
// 或者
auto lambda = [](int x) { cout << x << endl; };
print_lambda(lambda);
return 0;
}
在上述代码中,定义了一个函数print_lambda(),它接受一个使用int类型参数的lambda表达式,并输出参数的值。但是如果在调用函数时,直接使用未指定类型的参数名x,则编译器无法确定参数的类型,导致编译错误。因此,在使用lambda表达式时,应该显式指定参数类型或使用auto关键字进行自动推导。
- 返回值类型的推导:
#include <iostream>
#include <functional>
using namespace std;
function<bool(int)> make_lambda() {
function<bool(int)> lambda = [](int x) {
if (x > 0) {
return true;
}
else {
return string("error"); // 编译器报错:转换类型不匹配
}
};
return lambda;
}
int main() {
auto lambda = make_lambda();
cout << lambda(10) << endl; // 输出结果为true
return 0;
}
在上述代码中,函数make_lambda()返回一个使用自动推导返回值类型的lambda表达式,并尝试返回两种不同的类型。但是由于编译器无法确定其返回值类型,会导致类型转换错误的编译错误。因此,如果lambda表达式中存在多个可能的返回类型,应该显式指定返回值类型以避免出现错误。
- 捕获列表中变量的初始化:
#include <iostream>
#include <functional>
using namespace std;
void print_lambda(function<void()> lambda) {
lambda();
}
int main() {
int x = 42;
// 初始化一个捕获列表中的变量
auto lambda = [x = x]() mutable {
cout << x << endl;
x++;
};
print_lambda(lambda); // 输出结果为42
print_lambda(lambda); // 输出结果为42
return 0;
}
在上述代码中,lambda表达式使用了初始化语法来初始化捕获列表中的变量x。但是由于每次调用lambda表达式时都会生成一个新的实例,因此如果直接在捕获列表中初始化x,则每个实例都会使用相同的初始值,导致其他lambda表达式的调用结果无法正确反映出更改后的变量值。因此,为了避免这种问题,应该将初始化移到lambda表达式的函数体内部,以便每次调用都能得到正确的值。
本文来自博客园,作者:flxx,转载请注明原文链接:https://www.cnblogs.com/faithlocus/p/17286651.html