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

C++使用auto声明lambda变量触发std::bad_function_call异常问题咨询

问题原因分析
  • 每个lambda表达式在编译期都会生成一个独有的匿名类类型,不是std::function<void()>类型。当你用auto声明lambda变量时,变量的类型就是这个匿名类类型,而非std::function。
  • 你的类A构造函数接收的是const std::function<void()>&类型参数,当你传入auto声明的lambda时,编译器会隐式生成一个临时的std::function<void()>对象来匹配参数类型。这个临时对象的生命周期仅持续到构造函数调用语句结束,构造函数中你将这个临时对象的地址存入成员指针m_Lambda,构造完成后临时对象被销毁,m_Lambda变成悬垂指针,调用ExecuteLambda解引用悬垂指针就会抛出std::bad_function_call异常。
  • 当你把lambda变量显式声明为const std::function<void()>类型时,变量本身就是生命周期和main函数同步的左值对象,构造函数取的是这个有效对象的地址,因此运行正常。
可使用auto声明lambda的场景

满足以下条件的场景都可以用auto声明lambda变量:

  • 直接传递lambda给函数模板(比如STL算法的回调参数),不需要将其转换为std::function长期持有
  • 持有lambda本身的实例而非转换后的std::function的指针/引用
  • 不需要通过基类/类型擦除接口存储lambda的场景
保留auto声明的修复方案

不需要修改lambda的auto声明,只需要调整类A的设计即可,核心是避免存储临时对象的地址:

方案1:类A直接存储std::function实例(推荐)

将成员变量从指针改为存储std::function实例,构造时直接转移lambda的所有权,不存在悬垂风险:

#include <iostream>
#include <functional>

class A
{
    std::function<void()> m_Lambda;
public:
    A(std::function<void()> lambda): m_Lambda(std::move(lambda)) {}

    void ExecuteLambda()
    {
        m_Lambda();
    }
};

int main() // 标准C++要求main返回int,void是MSVC扩展
{
    int i1 = 1;
    int i2 = 2;
    
    const auto lambda = [&]()
    {
        std::cout << "i1 == " << i1 << std::endl;
        std::cout << "i2 == " << i2 << std::endl;
    };

    A a(lambda);
    a.ExecuteLambda();
    return 0;
}

方案2:模板化类A直接存储lambda类型

如果不想引入std::function的类型擦除开销,可以将类A模板化,直接存储lambda的实例:

template<typename Func>
class A
{
    Func m_Lambda;
public:
    A(Func lambda): m_Lambda(std::move(lambda)) {}
    void ExecuteLambda()
    {
        m_Lambda();
    }
};

// C++17及以上支持类模板推导,可直接传入auto声明的lambda构造对象
A a(lambda);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 13:06:04