【问题标题】:The scope of local variables captured by a lambda function (C++)lambda 函数 (C++) 捕获的局部变量的范围
【发布时间】:2020-02-13 02:16:21
【问题描述】:

我到处搜索,但找不到我的问题的答案。我正在尝试编写一个示例,该示例表明通过引用捕获封闭函数的局部变量是危险的,因为它在实际引用时可能不再存在。这是我的例子:

#include <iostream>


std::function<int (int)> test2(int l) {
       int k = 10;
       return [&] (int y) { return ++k + 100; };
}


void test(std::function<int (int)> k) {
        std::cout << k(100);
}

int main() {
        test(test2(100));

        std::function<int (int)> func = test2(100);
        test(func);

        return 0;
}

我试图通过从 test2 返回捕获局部变量 k 的 lambda 函数来访问和修改堆栈帧上不存在的局部变量,从而重现堆栈损坏 并对其进行修改。

std::function<int (int)> func = test2(100);
test(func);

打印出一个垃圾值,表明出现了预期的问题。不过,

test(test2(100));

打印出“111”。这让我感到困惑,因为我认为当 test2(100) 返回 std::function 类型的 lambda 函数时,test2 的堆栈框架将消失,并且当调用 test 时,它应该无法访问 k 的值.我会很感激我可以用来搜索答案的任何想法或关键字。

【问题讨论】:

  • 这是未定义的行为。在它消失后访问k 可以做任何事情,包括打印垃圾。
  • 没有办法普遍检测未定义的行为。某些工具在某些情况下可能会有所帮助,例如各种类型的clang sanitizers
  • 打印垃圾(或崩溃)只有在行为未定义时才有可能。不能保证。太多人认为打印垃圾或崩溃总是在行为未定义时发生。彻底清除这个概念。
  • 始终获得一个非垃圾值,表明局部变量 k 可能仍然可以访问,这意味着编译器(在我的例子中是 clang++ 3.9)可能以不同的方式处理两种情况,或者它可能是一个错误。我正在考虑这些可能性。

标签: c++ function lambda stack call


【解决方案1】:

我已经在我的机器上运行了你的测试,结果在这两种情况下都是预期的垃圾。以这种身份偶尔有一个正确的答案是非常具有误导性的。只要指向的内存尚未被其他值占用,悬空引用或指针可能偶尔会指向相同的值。

简而言之,C++ lambda 不会延长捕获的引用/指针的生命周期,但它们的引用堆栈会展开。同样的事情也适用于捕获类的“this”指针。如果类超出范围,“this->”将导致完全未定义的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-13
    • 1970-01-01
    相关资源
    最近更新 更多