lambda的捕获变量被重置 [英] lambda's captured variable is reset
问题描述
我正在尝试在项目中使用 lambda
,但是我想我缺少关于闭包范围的信息。我测试了这段代码,以某种方式简化了我的问题。
I'm trying to use lambda
s inside a project but I think I'm missing something about the closure's scope. I tested this piece of code which in some way is a simplification of my problem.
#include <iostream>
#include <functional>
using namespace std;
void tester_wrapper(std::function<int(void)> cb, int counter){
if (counter == 10)
return;
else{
cout << cb() << endl;
tester_wrapper(cb, counter + 1);
}
}
void tester(std::function<int(void)> cb){
tester_wrapper(cb, 0);
}
int main()
{
auto getNum = ([](int starter) {
return [starter]() mutable {
return ++starter;
};
})(1);
tester(getNum);
tester(getNum);
}
首次调用 tester $ c之后$ c>捕获的变量
starter
被重置,以便相同的输出被打印两次。
After the first call to tester
the captured variable starter
is reset so that the same output is printed twice.
我该怎么办为了避免lambda的内部计数器( starter
)的这种行为?本质上,第二次调用 tester
的呼叫必须打印从12而不是2开始的10个数字。
What should I do in order to avoid this behaviour of the inner counter(starter
) of the lambda? Essentially the second call to tester
has to print 10 numbers starting from 12 instead of 2.
编辑
感谢您的回答。我没有考虑过要将副本传递给 tester_wrapper
,所以我找到了以下解决方案:
Thank you for the answers. I have not considered that I was passing a copy to tester_wrapper
, so I've found this solution:
#include <iostream>
#include <functional>
using namespace std;
std::function<int(void)> mylambda(int starter){
return [starter]() mutable {
return ++starter;
};
}
void tester_wrapper(const std::function<int(void)>& cb, int counter){
if (counter == 10)
return;
else{
cout << cb() << endl;
tester_wrapper(cb, counter + 1);
}
}
void tester(const std::function<int(void)>& cb){
tester_wrapper(cb, 0);
}
int main()
{
/*auto getNum = ([](int starter) {
return [starter]() mutable {
return ++starter;
};
})(1);*/
auto getNum = mylambda(1);
tester(getNum);
tester(getNum);
}
但是,现在我不明白为什么旧的 getNum
使用外部函数( mylambda
)输出相同的输出,但输出相同。
However, now I can't understand why the old getNum
print the same output while it's different using an "external" function, which is mylambda
.
(我应该为此发布一个新问题吗?)
(Am I supposed to post a new question for this?)
推荐答案
该变量未重置,这是变量的另一个副本。实际上,有一堆副本。第一个处于您创建的lambda的状态。第二个是在构造第一个 std :: function
时创建的。您必须记住,它将接收到的可调用对象复制到其自身中。因此,每次 tester
的调用都会启动一连串的副本。解决该问题的一种方法是在 std :: reference_wrapper
。
The variable isn't reset, it's a different copy of the variable. In fact, there are a bunch copies. The first is in the state of the lambda you create. The second is created when the first std::function
is constructed. You must remember that it copies the callable it receives into itself. So each invocation of tester
starts a chain of copies. One way to get around it, is to pass the lambda inside a std::reference_wrapper
.
tester(std::ref(getNum));
tester(std::ref(getNum));
将复制引用包装,但所有副本将引用同一个lambda对象, getNum
。
The reference wrapper will be copied, but all copies will refer to the same lambda object, getNum
.
现在,假设您打算创建许多不同的对象,例如 getNum
, std :: function
及其提供的类型擦除是避免可能的代码膨胀的合理做法。要记住的是不要创建多余的副本。因此,按值接受 tester
是合法的,但 tester_wrapper
应该代替引用。这样一来,您只需在API边界的所需位置购买类型擦除即可。
Now, assuming you intend to create many different objects like getNum
, a std::function
and the type erasure it provides are a reasonable course of action to avoid possible code bloat. The thing to remember is to not create superfluous copies. So tester
accepting by value is legitimate, but tester_wrapper
should accept by reference instead. That way, you'll only pay for the type erasure in the one place you need it, at the API boundary.
这篇关于lambda的捕获变量被重置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!