c++ Lambda内回路

4zcjmb1e  于 2023-06-25  发布在  其他
关注(0)|答案(3)|浏览(95)

我在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,它建议不要使用会使迭代器无效的容器。
为什么会这样?

i7uaboj4

i7uaboj41#

指定捕获时,可以选择按值捕获和按引用捕获。您已选择通过引用捕获。通过引用捕获意味着lambda函数中的变量引用同一个对象。这意味着对该变量的任何更改都将被共享,并且您还需要确保被引用的对象在lambda函数的生命周期内一直存在。
你可能是想通过价值观来捕捉。为此,您可以将捕获规范替换为[=][x]。后者确保只能访问x,而前者则允许访问其他变量。
顺便说一句,我建议不要显式地使用lock()unlock(),而是使用其中一个锁保护。这样,循环的主体看起来就像这样:

vec.push_back(std::thread{[x](){
    std::lock_guard<std::mutex> kerberos(m);
    std::cout << x << "\n";
}});
svdrlsy4

svdrlsy42#

如果你想复制一个参数,请按 value 捕获参数,而不是按引用捕获:

vec.push_back(std::thread{[x](){
  m.lock();
  std::cout << x << std::endl;
  m.unlock();
}});

这将复制创建lambda对象时x的值(而不是线程启动时)。
在我寻找答案的过程中,我偶然发现了这个问题Generalizing C11 Threads class to work with lambda,它建议不要使用会使迭代器无效的容器。为什么会这样/
因为它讨论的是一个完全不同的实现,它直接使用pthreads库。您使用的是std::thread,它设计用于C

bvk5enib

bvk5enib3#

问题是你正在通过引用捕获x。因此,当x在每个循环结束时递增时,这反映在线程中。
您希望通过值捕获x,以便lambda在创建lambda时只使用x的值。

for( int x = 0; x < n; ++x)
{               
   vec.push_back(thread{[x](){
      m.lock();
      cout << tmp << endl;
      m.unlock();
   }});
}

相关问题