You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何C++ Lambda会导致析构函数被额外调用?

为什么不带&的auto参数无法匹配std::function期望的引用类型?

测试程序

#include <iostream>
#include <functional>

struct Foo
{
    inline Foo() {
        std::cout << "foo constructor" << std::endl;
    }

    inline ~Foo() {
        std::cout << "foo destructor" << std::endl;
    }
};

void NotBroken()
{
    Foo foo;
    std::function<void(Foo&)> callback;
    callback = [](auto&) { // <- 注意这里的auto&
        std::cout << "executed callback" << std::endl;
    };
    callback(foo);
}

void TotallyBroken()
{
    Foo foo;
    std::function<void(Foo&)> callback;
    callback = [](auto) { // <- 注意这里没有&的auto
        std::cout << "executed callback" << std::endl;
    };
    callback(foo);
}

int main()
{
    NotBroken();
    std::cout << std::endl;
    TotallyBroken();
}

运行输出

foo constructor
executed callback
foo destructor

foo constructor
executed callback
foo destructor
foo destructor

问题

不带&的auto参数为何无法识别std::function所期望的引用类型?在MSVC、Clang和GCC中均存在此行为,额外的析构函数调用发生在Lambda执行结束时。


解答

这是C++泛型Lambda推导规则与std::function适配逻辑共同作用的结果,完全符合标准规范:

  1. 泛型Lambda的参数推导逻辑
    泛型Lambda的auto参数推导和普通模板函数规则一致:当实参是引用类型时,推导会自动忽略引用属性。所以在[](auto)的场景中,传入的Foo&会被推导为Foo值类型,Lambda的实际参数类型就是Foo(值传递)。

  2. std::function的适配过程
    std::function<void(Foo&)>要求可调用对象能接收Foo&类型参数,但此时Lambda只接受Foo值类型。为了完成调用,std::function会把传入的Foo&隐式拷贝构造出一个临时Foo对象,传递给Lambda执行。这个临时对象会在Lambda执行完毕后立即销毁,因此多出现了一次析构调用。

  3. 带&的Lambda正常的原因
    当使用[](auto&)时,auto会被推导为Foo,最终Lambda的参数类型是Foo&,完全匹配std::function的要求。调用时直接传递原对象的引用,不会产生临时对象,因此只有一次析构。

如果希望Lambda参数保持引用语义,必须显式在auto后添加&(或&&实现万能引用),否则必然会触发值拷贝。


内容的提问来源于stack exchange,提问作者ProgramGamer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 20:10:30