代码之家  ›  专栏  ›  技术社区  ›  HiroIshida

成员变量lambda函数崩溃

  •  8
  • HiroIshida  · 技术社区  · 7 年前

    班级 montecarlo 包含lambda作为成员变量。此代码可以编译,但在运行时会导致“分段错误(核心转储)”。你能解释一下怎么修吗?

    #include<random>
    #include<functional>
    #include<iostream>
    
    class montecarlo
    {
      public:
        montecarlo(double x_min, double x_max);
        std::function<double()> rand;
    };
    
    montecarlo::montecarlo(double x_min, double x_max){
      std::random_device rd;
      std::mt19937 mt(rd());
      std::uniform_real_distribution<double> rand_(x_min, x_max); 
      rand = [&](){return rand_(mt);};
    }
    
    int main(){
      montecarlo x(0, 1);
      std::cout<<x.rand()<<std::endl;
    }
    

    让我疑惑的是,当我将构造函数的实现更改为下面的代码时,它工作了:

    montecarlo::montecarlo(double x_min, double x_max){
      rand = [](){return 0;};
    }
    

    你可能知道,但让我说,我要做的不仅仅是使用随机函数。

    3 回复  |  直到 7 年前
        1
  •  9
  •   songyuanyao    7 年前

    你想抓住 rand_ mt 通过引用;它们是内部的本地对象 montecarlo::montecarlo ,当外部调用lambda时 蒙地卡罗:蒙地卡罗 这些本地对象已被销毁,并且存储在lambda对象中的引用已被挂起。

    你可以把它改为拷贝捕获;注意你需要把lambda mutable 调用 兰特_ 有效。例如

    rand = [=]() mutable {return rand_(mt);};
    
        2
  •  5
  •   Marek R    7 年前

    这是未定义的行为,应该以分段错误结束。 注意,lambda通过引用捕获所有内容,它捕获的生命周期变量仅限于构造函数处理。所以当使用lambda时,它工作在不再存在的变量上。

    若要修复此问题,请将lambda更改为通过复制捕获变量,它将正常工作。

    或者将此变量设为类的字段。

        3
  •  4
  •   Caleth    7 年前

    在lambda中复制生成器和发行版的另一种方法是使它们成为类的成员。它们的寿命和 rand

    class montecarlo
    {
        std::mt19937 gen;
        std::uniform_real_distribution<double> dis;
      public:
        montecarlo(double x_min, double x_max);
        std::function<double()> rand;
    };
    
    montecarlo::montecarlo(double x_min, double x_max)
      : gen(std::random_device()), 
        dis(x_min, x_max),
        rand([this](){ return dis(gen); })
    {}
    

    这个类的名称表明它将执行其他操作。我不建议您扩展它,而是将生成分为自己的类。

    class uniform_real_generator
    {
        std::mt19937 gen;
        std::uniform_real_distribution<double> dis;
      public:
        uniform_real_generator(double x_min, double x_max);
        double operator();
    }
    
    uniform_real_generator::uniform_real_generator(double x_min, double x_max)
      : gen(std::random_device()), 
        dis(x_min, x_max)
    {}
    
    double uniform_real_generator::operator()
    {
        return dis(gen);
    }
    
    class montecarlo
    {
        // other members
    public:
        montecarlo(double x_min, double x_max/*, other args */);
        uniform_real_generator rand;
    }
    
    montecarlo::montecarlo(double x_min, double x_max/*, other args */)
      : rand(x_min, x_max) //, other member initialisers
    {}