Lambda内循环

Sau*_*ack 7 c++ lambda c++11

我在lambda中有一个lambda,在for循环中有一个loop变量参数.当我运行它时,我希望输出数字0-9.但由于它是一个lambda,x不会立即得到评估.

    for( int x = 0; x < n; ++x)
    {
            vec.push_back(thread{[&x](){
                    m.lock();
                    cout << x << endl;
                    m.unlock();
            }});
    }
Run Code Online (Sandbox Code Playgroud)

输出:

0
3
3
9
Run Code Online (Sandbox Code Playgroud)

等等

其他语言的解决方案是创建一个临时变量,

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

但这似乎不起作用.

请参阅接收错误参数的线程

奖金:

在我寻找答案的过程中,我偶然发现了这个问题, 概括了C++ 11 Threads类以使用lambda ,它建议不使用会使迭代器无效的容器.为什么会这样?

Die*_*ühl 11

指定捕获时,可以选择按值捕获和按引用捕获.您已选择通过引用捕获.通过引用捕获意味着lambda函数内的变量指的是同一个对象.这意味着对此变量的任何更改都将被共享,您还需要确保引用的对象在lambda函数的生命周期内保持不变.

你可能想要通过值捕获.为此,您可以替换捕获规范以成为[=]或变为[x].后者确保只有x前者可以访问其他变量才能访问.

顺便说一句,我建议不要使用lock()和unlock()明确,而是使用其中一个锁定防护装置.有了这个,你的循环体看起来像这样:

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

  • @SaulBack:不.你应该使用`lock_guard`.如果您只想锁定某些代码,请使用带有`{}`的显式块来包含锁定的代码.这是基本的RAII编码. (5认同)
  • @SaulBack:特别是在您想要使用 RAII 的复杂代码中,例如 `std::lock_guard&lt;std::mutex&gt;`!在这个**微不足道的**示例中,我可以看到它是不需要的,但是当它变得更复杂时,事情很快就会失控。如果您需要限制持有锁的范围,请使用范围,即一对大括号:`{ &lt;lock and code need it gone here&gt; }`。 (2认同)

Nic*_*las 6

如果要复制,请按值而不是按引用捕获参数:

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

这将复制xlambda对象创建时的值(而不是在线程启动时).

在我寻找答案的过程中,我偶然发现了这个问题,概括了C++ 11 Threads类以使用lambda,它建议不使用会使迭代器无效的容器.为什么会这样?

因为它讨论的是直接使用pthreads库的完全不同的实现.您正在使用std::thread,它旨在使用C++.