在嵌套的lambda中按值捕获指针会导致段错误

时间:2018-04-03 15:25:49

标签: c++ pointers lambda

首先,这是我遇到过的最模糊的问题,因此是最难提出的问题。我会尝试通过发布最少的代码并提供一些上下文来尽可能地表达这个问题。首先,这里是出现问题的代码:

// Before lambda, pointer variable in question is fine
menu->onSelect = [=] ()
{
    window->pushCallback('e', [=]()
    {
        // Here the pointer captured changes, causing a segfault later on
    }
};

现在就某些情况而言:

pushCallback的签名如下所示:

void Window::pushCallback(int key, std::function<void()> callback) {}

它存储一个函数,当调用第一个参数表示的键代码时调用该函数,在这种情况下&#39; e&#39;。

Menu :: onSelect也是一个std ::函数,存储了一个在选择菜单项时执行的函数。

现在这个问题的默默无闻是指针只在第二次单步执行代码时才会改变。请注意,这是一个交互式ncurses程序。但是我做了很多测试,发现指针在两条显示的注释行之间发生了变化。通过捕获嵌套lambda中的变量来显示突变。我还在引用它的所有类中创建了指针const。

1 个答案:

答案 0 :(得分:0)

你不能在嵌套的lambdas中使用自动成员捕获,因为在执行外部lambda之前不会执行内部lambda的捕获。我相信在pre-C ++之间存在一些差异14和C ++ 14/17但我不记得副手了。我会调查并更新我的答案。

另外,我依稀记得在G ++和Clang之间遇到一些差异,但这与编译器抱怨有关,而不是与导致段错误的实现差异有关。再一次,我会记得一次更新。

解决方法,明确捕获变量或将其保存在tmp变量中。

std::shared_ptr<int> ptr; // This assumes that you are talking about shared pointers since I don't think you would have this problem with raw pointers unless the object is being destroyed before your lambda is being invoked
auto x = [ptr]()
     {
         // You could also create a temporary variable here to avoid ambiguity
         // std::shared_ptr<int> ptr2;
         return [ptr]() { return ptr; };
     };

我证实了我原来的假设是错误的。在这种情况下,共享点可以正常工作(但请确保您没有通过引用传递或所有投注都已关闭)。

auto foo(std::shared_ptr<int> p)
{
    return [=](int x) { return [=](int y) { return *p + x + y; }; };
}

int main()
{
    auto p = std::make_shared<int>(42);

    auto func = foo(p);

    std::cout << func(1)(2) << std::endl;

    ++(*p);

    std::cout << func(1)(2) << std::endl;

    return 0;
}

我建议您查看gdb中的错误,如果您担心它会被更改,可能会在指针上设置硬件中断。