通过嵌套的lambda中的值捕获指针导致Segfault

Capturing pointer by value in nested lambda leads to segfault

本文关键字:指针 Segfault 嵌套 lambda      更新时间:2023-10-16

首先,这是我曾经遇到过的最晦涩的问题,因此是最难提出的问题。我将尝试通过发布最小代码并提供一些上下文来使这个问题尽可能地表达。首先,这里是问题发生的代码:

// 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) {}

在调用第一个参数表示的键代码时,它存储一个要调用的函数,在这种情况下," e"。

菜单:: OnSelect也是一个std ::函数,在选择菜单项时存储单个函数。

现在,这个问题的晦涩是,指针仅在第二次逐步浏览代码时发生变化。请注意,这是一个交互式ncurses程序。但是,我进行了很多测试,并发现了两个显示的评论行之间的指针变化。表明突变是通过捕获嵌套兰伯斯中的变量而发生的。我还将指针的指针const在所有参考的类中。

您不能在类似嵌套的lambdas中使用自动成员捕获Pre-C 14和C 14/17之间的一些差异,但我不记得副手。我会研究它并更新我的答案。

此外,我隐约记得遇到了G 和Clang之间的某些差异,但这与编译器抱怨有关,而不是导致Segfault的实施差异。再次,我记得我会更新。


工作,明确捕获变量或将其保存在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中的错误,如果您担心它正在更改,可能会在指针上设置硬件中断。