2016-01-23 71 views
2

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

我有一些代码是这样的:

#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(); 
    } 
}; 
+3

你正在通过引用捕获,并且在'Setup'完成后'funcB'不再存在,因此这样做不会很好地结束。 –

+0

更改为通过复制进行捕获无助于... – Clones1201

回答

3

你捕捉参照FuncB,但是当Setup回报,让你有一个悬空参考FuncB被破坏。

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

我想不出有什么办法让lambda捕获自己,就像你正在做的那样。

+0

您可以通过捕获指向自己的唯一指针的共享指针来进行自己的lambda捕获。首先制作一个指向空指针的共享指针,然后定义捕获共享指针(包含空白指针)的递归lambda并将其分配到它所包含的共享指针中的唯一指针。唯一的指针确保它被正确删除。 – Dugi

1

较小修改你的代码,并能正常工作:

#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; 
} 

也许这将帮助您优化算法。

相关问题