【问题标题】:C++: Destroying lambda within himself [duplicate]C ++:在自己内部破坏lambda [重复]
【发布时间】:2026-01-25 14:10:02
【问题描述】:
#include <iostream>
#include <functional>

int global = 9;
std::function<void()> functor;

int main()
{
    int* ptr = &global;
    functor = [ptr]
    {
        functor = nullptr;
        std::cout << *ptr << std::endl;
    };

    functor();
}

这里是lambda捕获的变量ptr,在functor()调用过程中,仿函数首先通过functor = nullptr删除,然后访问ptr。我认为ptr 已损坏,因为它是已删除函子的字段。所有编译器都成功地执行了该程序而没有崩溃并打印“9”,但我仍然怀疑这不是未定义的行为。有人可以确认吗?

【问题讨论】:

  • @keith 我不认为这是完全重复的。这个问题是关于删除本身的,这个问题似乎集中在兰巴捕获的ptr
  • @Whatever:是的,这是完全重复的(std::function 是一个最大尺寸为 1 的容器)

标签: c++ c++11 lambda


【解决方案1】:

确实是未定义的。

您可以通过以下方式确认:

#include <iostream>
#include <functional>

struct S
{
    ~S() {std::cout << "~S()\n";}
};

std::function<void()> functor;

int main()
{
    functor = [s = S()]
    {
        functor = nullptr;
        std::cout << "End of lambda\n";
    };

    functor();
}

上面的代码打印(在 GCC 和 Clang 上):

~S()
~S()
~S()
End of lambda

3 个被销毁的实例是:一个由原始 lambda 捕获,一个由存储在 functor 中的副本捕获,一个由 std::function::operator=(F &amp;&amp;) 出于某种原因 has to make 的临时捕获。

【讨论】:

  • 实际上你看到了三个析构函数,因为 function::operator=(F&&) 是根据交换实现的,它创建了 lambda 的额外副本。为了验证这一点,您可以将 f 设为局部变量,并在声明期间对其进行初始化 - 您将只看到 2 个 S 析构函数调用。