搜索

首页  >  问答  >  正文

c++ - lambda 递归为何会crash

下面这段代码运行会crash

1

2

3

4

5

6

7

8

9

10

11

12

<code>#include <iostream>

#include <windows.h>

int main() {

        std::function<void()> fun = [=]{

                std::cout << "AAA" << std::endl;

                Sleep(1000);

                fun();

        };

        fun();

        return 0;

}

</code>

复制代码
把[=]改成[&] 就能通过了

1

2

3

4

5

6

7

8

9

10

11

12

<code>#include <iostream>

#include <windows.h>

int main() {

        std::function<void()> fun = [&]{

                std::cout << "AAA" << std::endl;

                Sleep(1000);

                fun();

        };

        fun();

        return 0;

}

</code>

复制代码
而我的函数需要用[=]方式,为啥会crash呢

巴扎黑巴扎黑2809 天前728

全部回复(2)我来回复

  • ringa_lee

    ringa_lee2017-04-17 12:59:58

    fun要先构造再调用,但是由于是值拷贝,所以在fun构造的时候拷贝的那个fun就可能是不完整的。

    1

    2

    3

    <code>warning: variable 'fun' is uninitialized when used within its own initialization [-Wuninitialized]

                    fun();

                    ^~~</code>

    如果一定要连fun也拷贝(按值捕获),可以采用delay的方式:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    <code>#include <iostream>

    #include <windows.h>

    int main() {

            std::function<void()> fun = [=, &fun]{

                    std::function<void()> delayFun = [&]{

                            std::function<void()> funCopy = fun;

                            funCopy();

                    };

                    std::cout << "AAA" << std::endl;

                    Sleep(1000);

                    delayFun();

            };

            fun();

            return 0;

    }</code>

    这样既无warning,程序行为也符合预期。

    回复
    0
  • 大家讲道理

    大家讲道理2017-04-17 12:59:58

    第一段代码,你是用拷贝的方式实现fun()函数的,也就是每次fun()被调用的时候就会同时拷贝一份,然后拷贝里面又会拷贝,这样重复若干次以后就会有很多个fun()在同时递归,这是一个几何增长的过程。这有点像linux中的fork函数,如果把fork写在循环里,那fork出来的进程也是一个几何增长的过程。但是这个复制 递归的过程还是比较复杂的,难以用一句话解释清楚。感兴趣的话可以去搜一搜fork相关的文章,对你理解这个问题会有帮助

    第二段代码不会拷贝出新的函数,所以只有一个fun()在递归,这是一个线性增长的过程(但是在递归达到极限时仍然会crash的,只是需要的时间很长,因为你2次递归之间会间隔1秒钟。如果你把Sleep()去掉应该就会看到它crash了)

    回复
    0
  • 取消回复