在lambda中捕获std :: function对象

时间:2013-11-29 18:06:59

标签: c++ c++11 compiler-construction lambda clang

当我在最后一行调用s_capture_void_int()时,代码在BAD_ACCESS失败,我不明白为什么。我想当我将lambda表达式赋给全局变量时,它应该将自己与捕获的值一起复制。所以在我的理解中,不应出现悬挂引用。但看起来我错过了什么。

std::function<void()> s_capture_void_int;
void capture_void_int (const std::function<void(int)>& param)
{
    s_capture_void_int = [param]() {
        param(1);
    };
}
void capture_local_lambda()
{
    auto local_lambda = [](int) {
    };
    s_capture_void_int = [local_lambda]() {
        local_lambda(1);
    };
}
BOOST_AUTO_TEST_CASE( test_lambda_captures )
{
    //Case 1: this works
    auto func2 = [](int){};
    {
        std::function<void(int)> func2_fn(func2);
        s_capture_void_int = [func2_fn]() { func2_fn(1); };
    }
    s_capture_void_int();

    //case 2: even this works.
    capture_local_lambda();
    s_capture_void_int();

    //case 3: but this fails.
    auto func3 = [](int){};
    {
        std::function<void(int)> func3_fn(func3);
        capture_void_int(func3_fn);
    }
    s_capture_void_int(); //<- it crashes here
}

我不明白这里有两件事:

  • 如果由于func3_fn超出范围而发生崩溃,那么为什么是情况1 和2作品?
  • 如果我将此代码更改为std :: function(注意没有参数),那么它可以正常工作。它可能是编译器错误吗?

2 个答案:

答案 0 :(得分:1)

我说这是编译错误。它works fine in GCC。也许param中的capture_void_int被引用错误地捕获(因为它是引用),而应该通过值捕获它。

答案 1 :(得分:1)

对于遇到同样问题的人。这确实是一个编译器错误,我找到了简单而愚蠢的解决方法。解决方法未经过测试,但至少我的程序在第一次调用std :: function时不会立即发生段错误。 使用Xcode 5.0.2和5.1编译器附带的clang出现问题。 gcc 4.8和可能的股票clang没有这个问题。最简单的程序来触发问题:

#include <iostream>
#include <functional>

std::function<void()> buggy_function;
/*
void workaround (const std::function<void(int)>& param)
{
    auto a = [&,param]() {
        param(1);
    };
}
*/
void trigger_bug (const std::function<void(int)>& param)
{
    buggy_function = [&,param]() {
        param(1);
    };
}

int main(int argc, const char * argv[])
{
    auto func3 = [](int){};
    std::function<void(int)> func3_fn(func3);
    trigger_bug(func3_fn);
    buggy_function();
    return 0;
}

如果您取消注释&#39;解决方法&#39;它神奇地开始工作。函数顺序很重要,解决方法函数必须在使用std :: function之前的任何其他函数之前。如果你把'解决方法'&#39;在下面&#39; trigger_bug&#39;然后它停止工作。