我在for循环中有一个lambda,lambda中有循环变量参数。当我运行它时,我期望输出数字0-9。但由于它是一个lambda,x不会立即被求值。
for (int x = 0; x < n; ++x)
{
vec.push_back(thread{[&x]() {
m.lock();
cout << x << endl;
m.unlock();
}});
}
输出:
0
3
3
9
etc.
其他语言的解决方案是创建一个临时变量,
for (int x = 0; x < n; ++x)
{
int tmp = x;
vec.push_back(thread{[&tmp]() {
m.lock();
cout << tmp << endl;
m.unlock();
}});
}
但好像不管用
参见Threads receiving wrong parameters
额外奖励:
在寻找答案的过程中,我偶然发现了这个问题Generalizing C++11 Threads class to work with lambda,它建议不要使用会使迭代器无效的容器。
为什么会这样?
3条答案
按热度按时间i7uaboj41#
指定捕获时,可以选择按值捕获和按引用捕获。您已选择通过引用捕获。通过引用捕获意味着lambda函数中的变量引用同一个对象。这意味着对该变量的任何更改都将被共享,并且您还需要确保被引用的对象在lambda函数的生命周期内一直存在。
你可能是想通过价值观来捕捉。为此,您可以将捕获规范替换为
[=]
或[x]
。后者确保只能访问x
,而前者则允许访问其他变量。顺便说一句,我建议不要显式地使用
lock()
和unlock()
,而是使用其中一个锁保护。这样,循环的主体看起来就像这样:svdrlsy42#
如果你想复制一个参数,请按 value 捕获参数,而不是按引用捕获:
这将复制创建lambda对象时
x
的值(而不是线程启动时)。在我寻找答案的过程中,我偶然发现了这个问题Generalizing C11 Threads class to work with lambda,它建议不要使用会使迭代器无效的容器。为什么会这样/
因为它讨论的是一个完全不同的实现,它直接使用pthreads库。您使用的是
std::thread
,它设计用于C。bvk5enib3#
问题是你正在通过引用捕获x。因此,当x在每个循环结束时递增时,这反映在线程中。
您希望通过值捕获x,以便lambda在创建lambda时只使用x的值。