在 lambda 函数声明中使用 auto

Using auto in lambda function declaration

什么时候可以 auto 用作用 lambda 函数初始化的变量的类型说明符?我尝试在以下程序中使用 auto

#include <iostream>
#include <functional>

class A
{
    const std::function <void ()>* m_Lambda = nullptr;

public:
    A(const std::function <void ()>& lambda): m_Lambda (&lambda) {}

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

void main()
{
    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();
}

我正在使用 Visual Studio Community 2019,当我开始执行 a.ExecuteLambda() 时,程序停止并出现以下异常:

Unhandled exception at 0x76D9B5B2 in lambda.exe: 
Microsoft C ++ exception: std :: bad_function_call at memory location 0x00B5F434.

如果我将行 const auto lambda = [&]() 更改为 const std::function <void ()> lambda = [&](),它会完美运行。为什么不允许使用auto?可以更改某些内容以允许使用它吗?

您在 A 对象中存储了一个 悬挂 std::function 指针

lambda 表达式不是 std::function 对象,它是编译器定义的类型,可以 分配 std::function 对象。

当您使用 auto 声明 lambda 时,它会获得一个唯一的类型。要将此 lambda 绑定到 A 构造函数的参数,将创建一个 temporary std::function 对象,您正在存储指向该对象的指针。但是,temporary 在构造函数退出时被销毁,这就是为什么在尝试执行 std::function.

时会出现异常的原因

当您将 lambda 的声明更改为 std::function 时,A 构造函数的参数能够按原样绑定到该对象,并且不会创建临时对象。

您应该按值而不是指针传递和存储 std::function 对象,例如:

#include <iostream>
#include <functional>

class A
{
    std::function<void()> m_Lambda;

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

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

int main()
{
    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;
}

Online Demo

lambda 表达式不会产生 std::function。相反,它创建了一个未命名的唯一 class 类型,并且具有 operator() 的重载。当您将 lambda 传递给 A 的构造函数时,它会创建一个临时 std::function 对象,并存储指向该临时对象的指针。当 A 的构造函数结束时,该临时对象被销毁,留下一个悬空指针。

要解决此问题,只需摆脱使用指针即可。那看起来像

#include <iostream>
#include <functional>

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

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

void main()
{
    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();
}