【问题标题】:Using auto in lambda function declaration在 lambda 函数声明中使用 auto
【发布时间】:2021-09-29 21:11:53
【问题描述】:

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 = [&amp;]() 更改为const std::function &lt;void ()&gt; lambda = [&amp;](),它会完美运行。为什么不允许使用auto?可以更改某些内容以允许使用它吗?

【问题讨论】:

    标签: c++ exception lambda std-function


    【解决方案1】:

    lambda 表达式不会产生std::function。相反,它创建了一个未命名的唯一类类型,并且具有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();
    }
    

    【讨论】:

      【解决方案2】:

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

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

      当您使用auto 声明lambda 时,它会获得一个唯一类型。要将此lambda 绑定到A 构造函数的参数,需要创建一个临时 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

      【讨论】:

        猜你喜欢
        • 2021-12-20
        • 1970-01-01
        • 2011-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多