为什么循环中的lambda函数没有按值捕获参数?

时间:2016-05-07 07:48:53

标签: c++ c++11 lambda

我有以下代码块,我期望lambda捕获列表中的i按值传递,并且i输出应该是不同的。

然而,实际结果是输出20行19 is completed

我尝试将此行std::thread t([&func](){更改为std::thread t([func](){,输出可能会打印不同的i值。

我的问题是为什么std::thread t([&func](){std::thread t([func](){将导致i的不同输出值?

void DoSomething(std::function<void()> func)
{
    std::thread t([&func](){
        //do something
        sleep(1);
        if (func)
            func();
    });
    t.detach();
}

int main(int argc, const char * argv[]) {
    std::mutex mtx;
    for (int i = 1 ; i < 20; i ++) {
        DoSomething([i, &mtx](){
            std::unique_lock<std::mutex> lock(mtx);
            std::cout << i << " is completed" << std::endl;;
        });
    }
    sleep(10);
}

3 个答案:

答案 0 :(得分:2)

您正在捕获对DoSomething参数func的引用。
当你的线程执行时,该参数的生命周期已经结束,所以你有一个悬空引用并且使用它是未定义的。

答案 1 :(得分:0)

t中的线程对象DoSomething()接收对func对象的引用,该引用按值传递。执行func()时,可能正在等待调用mutex的{​​{1}}。同时将调用std::unique_lock<std::mutex> lock(mtx);并通过销毁by值退出该函数参数t.detach()。如@molbidnilo所说,这将导致悬空参考。

问题可以通过调用func而不是t.join();来解决。

答案 2 :(得分:0)

如果使用t.detach(),则线程独立运行,现在你通过引用传递函数对象,所以如果在独立线程试图引用时销毁了函数对象,那么这不会导致崩溃该程序。 但是如果按值传递函数对象,则会解决此问题。我在我的机器上测试了你的代码,它在通过引用使用传递的函数对象时崩溃了。

相关问题