【问题标题】:Why can't I capture a recursive lambda function in C++?为什么我不能在 C++ 中捕获递归 lambda 函数?
【发布时间】:2016-01-23 15:48:57
【问题描述】:

我发现如果一个 lambda 是一个调用自身的递归函数,那么它不能被另一个 lambda 捕获为在 C++ 中的闭包中工作。

我有一些这样的代码:

#include <memory>
#include <functional>
#include <iostream>

class ClassA
{
public:
    std::function<void()> FuncA;
    void Call()
    {
        FuncA();
    }
};

class ClassB
{
    std::unique_ptr<ClassA> pA = std::make_unique<ClassA>();
public:
    void Setup()
    {
        std::function<void(int)> FuncB = [&](int a)
        {
            std::cout << "a = " << a << std::endl;
            if(a > 0)
                FuncB(a-1);
        };

        pA->FuncA = [&]()
        {
            FuncB(10.0f);
        };
    }
    void Run()
    {
        Setup();
        pA->Call();
    }   
};

int main() {

    ClassB B;
    B.Run();
}

运行调用FuncA时会出现异常,因为其中的FuncB会是一个空指针。

我的问题是为什么我不能捕获递归 lambda 函数?

我正在使用 Visual Studio 2015

编辑: 如果在 FuncA 中通过副本捕获 FuncB,则如果 FuncB 不是递归的,则它可以工作。像这样:

class ClassB
{
    std::unique_ptr<ClassA> pA = std::make_unique<ClassA>();
public:
    void Setup()
    {
        std::function<void(int)> FuncB = [FuncB](int a)
        {
            std::cout << "a = " << a << std::endl;
            if (a > 0)
                FuncB(a - 1);
        };

        pA->FuncA = [FuncB]()
        {
            FuncB(10.0f);
        };
    }
    void Run()
    {
        Setup();
        pA->Call();
    }
};

【问题讨论】:

  • 你正在通过引用捕获,funcBSetup 完成后不再存在,所以是的,这不会很好地结束。
  • 更改为按副本捕获无济于事...

标签: c++ recursion lambda


【解决方案1】:

您正在通过引用捕获FuncB,但FuncBSetup 返回时被销毁,留下一个悬空引用。

如果您将 FuncB 更改为按值捕获,则第一个 lambda 在初始化之前捕获它,这会导致未定义的行为。

我想不出任何方法来让 lambda 捕获自己,就像你正在尝试做的那样。

【讨论】:

  • 您可以让 lambda 捕获自身,方法是让它捕获指向自身的唯一指针的共享指针。首先,您创建一个指向空唯一指针的共享指针,然后定义捕获共享指针(包含空白指针)的递归 lambda,并将其分配给它包含的共享指针中的唯一指针。唯一指针确保它被正确删除。
【解决方案2】:

对你的代码做了一些小的修改,效果很好:

#include <iostream>
#include <functional>

struct A
{
    std::function<void()> fa;
    void call() { fa(); }
};

struct B
{
    A *pA;
    B() {pA=nullptr; }
    typedef std::function<void(int)> FB;
    FB fb;
    void Setup()
    {
        fb=[&](int i)
        {
            std::cout << "i = " << i << "\n";
            if(i > 0) fb(i-1);
        };
        if (pA) { pA->fa=[&]() { fb(10.0f); }; }
    }
    void Run(A*p)
    {
        pA=p;
        Setup();
        pA->call();
    }
};

int main()
{
    A a;
    B b;
    b.Run(&a);
    return 0;
}

也许这会帮助你完善你的算法。

【讨论】:

    猜你喜欢
    • 2019-09-13
    • 1970-01-01
    • 2013-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 2014-01-18
    相关资源
    最近更新 更多