在 C++ 中捕获函数的局部变量的闭包的行为

Behaviour of a closure that captures a local variable of function that it was returned from, in C++

提问人:vikram2784 提问时间:11/5/2021 最后编辑:vikram2784 更新时间:11/5/2021 访问量:119

问:

我有点困惑为什么以下功能和行为不同。当然,一个返回一个闭包,另一个返回对局部变量的引用。但从本质上讲,前一个返回值(闭包)在调用时会做同样的事情,即返回对返回它的函数的局部变量的引用。normal_get()closure_get()

我不是 c++ 专家,我知道不能返回对函数中局部变量的引用。但是我想确认它是否是闭包场景的未定义或预期行为,并且那里没有编译器魔术?(问,因为我最近开始在 C++ 中玩闭包)

我正在使用 g++ 9.3.0

g++ -std=c++2a test.cpp


#include <iostream>
#include <functional>

using namespace std;


auto closure_get() {
        int val = 10;

        auto f = [&]() {       // capturing by reference
                return &val;
        };

        return f;
}

auto normal_get() {
        int val = 10;

        return &val;
}


int main () {
        auto func = closure_get();
        auto val = normal_get();

        std::cout<<*func()<<std::endl;  // This always prints `10`. Should this be considered as undefined behavior though?
        std::cout<<*val<<std::endl;     // This always segfaults as expected. It's still undefined behavior even if it prints some value.
}

C++ 堆栈 闭包

评论

10赞 NathanOliver 11/5/2021
所有代码都具有未定义的行为。无论您得到什么结果都是“正确的”。不能返回指向非静态函数本地对象的指针/引用,因为它们会在函数结束时销毁。
0赞 vikram2784 11/5/2021
是的,我明白。出现段错误的那个,或者即使它返回一些垃圾或本地值,仍然是一个未定义的行为。我只是想确认另一种情况,即返回闭包的情况,因为这似乎永远不会出现段错误/或打印垃圾值。
4赞 Richard Critten 11/5/2021
看似有效是未定义行为的一部分。
0赞 vikram2784 11/5/2021
是的,只是想排除那里的任何编译器魔术。
1赞 Ted Lyngmo 11/5/2021
@vikram2784 那么你质疑它的本能是好的。希望这本书能解释两者都有UB - 或者这是一本蹩脚的书。编辑:我不知道为什么我一直说“书”。感觉就像来自一本书。

答:

3赞 foragerDev 11/5/2021 #1

在这两种情况下,它都是未定义的行为,因为任何非静态局部变量都不能作为引用或指针返回,因为它在该函数的作用域结束后被销毁。因此,该引用或指针将无效。