作为成员变量的lambda函数崩溃

时间:2018-07-03 07:10:49

标签: c++ c++11 random lambda functional-programming

.mdc-text-field__input { box-sizing: initial; // or content-box } 包含lambda作为成员变量。该代码可以编译,但是会在运行时导致“分段错误(内核已转储)”。您能解释一下如何解决它吗?

montecarlo

让我感到奇怪的是,当我将构造函数的实现更改为下面的代码时,它起作用了:

#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;
}

您可能会知道,但是让我说我​​想做的不只是使用随机函数。

3 个答案:

答案 0 :(得分:9)

您正试图通过引用捕获rand_mt;它们是montecarlo::montecarlo内部的本地对象,当在montecarlo::montecarlo外部调用lambda时,这些本地对象已被破坏,并且存储在lambda对象中的引用已悬空。

您可以将其更改为通过副本捕获;并请注意,您需要使mutable的lambda生效,以使对rand_的调用有效。例如

rand = [=]() mutable {return rand_(mt);};

答案 1 :(得分:5)

这是未定义的行为,应以Segmentation Fault结尾。 请注意,您的lambda通过引用捕获所有内容,并且它捕获的生存期变量仅限于构造函数处理。因此,当使用lambda时,它将对不再存在的变量起作用。

要解决此问题,请更改lambda以通过复制捕获变量,它将起作用。

或者使此变量成为类的字段。

答案 2 :(得分:4)

在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
{}