C++ 理解可变捕获
如果我理解正确(我的源代码是《C++初级读本》第5版第395页),《代码》可变版本可以从C++ 理解可变捕获,c++,c++11,lambda,C++,C++11,Lambda,如果我理解正确(我的源代码是《C++初级读本》第5版第395页),《代码》可变版本可以从lambda中修改捕获的变量。有两件事我不明白: 这与通过引用捕获有什么不同?而且,如果通过引用捕获是下面发生的事情,那么mutable的目的是什么?只是一块糖 如果mutable可以在每个变量的基础上应用,不是更有帮助吗 mutable允许您修改lambda范围外定义的变量,但对这些变量所做的任何更改都不会扩展到初始变量: auto f1 = [=] () mutable { n += 4; return
lambda
中修改捕获的变量。有两件事我不明白:
mutable
的目的是什么?只是一块糖mutable
可以在每个变量的基础上应用,不是更有帮助吗mutable
允许您修改lambda范围外定义的变量,但对这些变量所做的任何更改都不会扩展到初始变量:
auto f1 = [=] () mutable { n += 4; return n ; } ;
auto f2 = [&] () { n += 4; return n ; } ;
std::cout << f1 () << ' ' ; // Call to f1, modify n inside f1
std::cout << n << ' ' ; // But not in main
// 2nd call to f1, the value of n inside f1 is the value stored during the first call,
// so 8 (the output will be 8 + 4)
std::cout << f1 () << ' ' ;
std::cout << f2 () << ' ' ; // Call to f2, modify n inside f2
std::cout << n << std::endl ; // And in main
另一个区别是,使用“按值捕获”时,在计算lambda时捕获值,而不是在调用lambda时捕获值:
int n = 4 ;
auto f1 = [=] () mutable { return n ; } ; // lambda evaluated, value is 4
auto f2 = [&] () { return n ; } ; // lambda evaluated, reference to n
std::cout << f1 () << ' ' ; // Call to f1, captured value is 4
std::cout << f2 () << ' ' ;
n = 8 ;
std::cout << f1 () << ' ' ; // Call to f1, captured value is still 4
std::cout << f2 () << std::endl ; // Reference to n, so updated value printed
最后一个(巨大的)区别是,一旦目标超出范围,引用捕获的变量就不可用:
std::function <int ()> f (bool withref) {
int n = 4 ;
if (withref) {
return [&] () { return n ; } ;
}
return [=] () { return n ; } ;
}
auto f1 = f (false) ;
auto f2 = f (true) ;
std::cout << f1 () << ' ' ;
std::cout << f2 () << std::endl ; // Something will go wrong here...
第二种行为尚未定义
总结如下:
- 使用
可以修改函数范围内由值捕获的变量,但由于在计算lambda时变量已复制到另一个内存位置,因此您只需修改变量的本地副本(您可以访问此副本,即使原始变量已消失)mutable
- 使用
不会创建原始变量的副本,允许您修改它(原始变量),但允许您在其«销毁»后访问此变量&
可变
允许您修改lambda范围外定义的变量,但对这些变量所做的任何更改都不会扩展到初始变量:
auto f1 = [=] () mutable { n += 4; return n ; } ;
auto f2 = [&] () { n += 4; return n ; } ;
std::cout << f1 () << ' ' ; // Call to f1, modify n inside f1
std::cout << n << ' ' ; // But not in main
// 2nd call to f1, the value of n inside f1 is the value stored during the first call,
// so 8 (the output will be 8 + 4)
std::cout << f1 () << ' ' ;
std::cout << f2 () << ' ' ; // Call to f2, modify n inside f2
std::cout << n << std::endl ; // And in main
另一个区别是,使用“按值捕获”时,在计算lambda时捕获值,而不是在调用lambda时捕获值:
int n = 4 ;
auto f1 = [=] () mutable { return n ; } ; // lambda evaluated, value is 4
auto f2 = [&] () { return n ; } ; // lambda evaluated, reference to n
std::cout << f1 () << ' ' ; // Call to f1, captured value is 4
std::cout << f2 () << ' ' ;
n = 8 ;
std::cout << f1 () << ' ' ; // Call to f1, captured value is still 4
std::cout << f2 () << std::endl ; // Reference to n, so updated value printed
最后一个(巨大的)区别是,一旦目标超出范围,引用捕获的变量就不可用:
std::function <int ()> f (bool withref) {
int n = 4 ;
if (withref) {
return [&] () { return n ; } ;
}
return [=] () { return n ; } ;
}
auto f1 = f (false) ;
auto f2 = f (true) ;
std::cout << f1 () << ' ' ;
std::cout << f2 () << std::endl ; // Something will go wrong here...
第二种行为尚未定义
总结如下:
- 使用
可以修改函数范围内由值捕获的变量,但由于在计算lambda时变量已复制到另一个内存位置,因此您只需修改变量的本地副本(您可以访问此副本,即使原始变量已消失)mutable
- 使用
不会创建原始变量的副本,允许您修改它(原始变量),但允许您在其«销毁»后访问此变量&
const
时,它的方法可以修改mutable
数据成员。但是在这里我选择声明哪些数据成员mutable
,而这里是all或none!@worldssender在你引用的帖子中解释了所有不同的选项工作(我知道lambda
基本上是一个未命名类的对象,所以这对我来说并不新鲜)。但是,我没有看到这个问题的答案:为什么我要使用mutable而不是[&]
?我看起来缺少了一些非常基本的东西,但我不知道它是什么…@MeirGoldenberg,当使用[&]时
您更改绑定lambda的作用域的变量。使用[=]mutable
时,您首先复制变量,但可以在lambda中对其进行变异1。这里回答了2。应该也很清楚,事后停止认为mutable是(仅)与lambdas相关。@deviantfan我不明白你的意思。当一个对象是const
时,它的方法可以修改mutable
数据成员。但是在这里我选择声明哪些数据成员mutable
,而这里是all或none!@worldssender在你引用的帖子中解释了所有不同的选项工作(我知道lambda
基本上是一个未命名类的对象,所以这对我来说并不新鲜)。但是,我没有看到这个问题的答案:为什么我要使用mutable而不是[&]
?我看起来缺少了一些非常基本的东西,但我不知道它是什么…@MeirGoldenberg,当使用[&]时
您更改了绑定lambda的作用域的变量。使用[=]mutable
时,您首先复制变量,但可以在lambda中对其进行变异谢谢!您真是一针见血!如果您使用f1
增量n
例如n+=4
并调用f1()
两次!@MeirGoldenberg是的,你是对的。它清楚地表明了一个事实,即有一个n
的副本与f1
相关(有一种带有初始值的静态变量)。我更新了我的答案。它不是一个静态变量。这是因为捕获的变量是lambda
对象的数据成员。@MeirGoldenberg我没有说它是,只是行为(几乎)与执行[\n=n](){static int n=\n;n+=4;返回n;}
没有mutable
关键字。谢谢!你真是一针见血!如果你增加f1
incrementn
例如n+=4
并调用f1()
两次!@MeirGoldenberg是的,你是对的,它清楚地表明了一个事实,即有一个n
的副本与f1
关联(有点像一个带有初始值的静态变量)。我更新了我的答案。它不是一个静态变量。这是捕获的变量是