2016-01-23 135 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; 
} 

也許這將幫助您優化算法。