A lambda function which is a member variable crashes

Multi tool use
A lambda function which is a member variable crashes
The class montecarlo
contains lambda as a member variable. This code can be compiled, but will cause "Segmentation fault(core dumped)" in run time. Could you explain how to fix it?
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;
}
And what made me wonder is when I change the constructor's implementation into the code below, it worked:
montecarlo::montecarlo(double x_min, double x_max){
rand = (){return 0;};
}
You would probably know, but let me say that what I want to do is not just using a random functions.
3 Answers
3
You're trying to capture rand_
and mt
by reference; they're local objects inside montecarlo::montecarlo
, when lambda is called outside montecarlo::montecarlo
these local objects have been destroyed and the references stored in lambda object have become dangled.
rand_
mt
montecarlo::montecarlo
montecarlo::montecarlo
You could change it to capture by copy; and note you need to make the lambda mutable
to make the invocation on rand_
valid. e.g.
mutable
rand_
rand = [=]() mutable {return rand_(mt);};
This is undefined behavior which should end with Segmentation Fault.
Note that your lambda captures everything by reference and life time variables it captures is limited to constructor processing. So when lambda is used it works on variables which do not exist anymore.
To fix it change lambda to capture variables by copy and it will work.
Or make this variables to be fields of the class.
I didn't meant that every UB leads to a crash (most of them don't), but this specific case should end with a crash.
– Marek R
Jul 6 at 10:44
An alternative to copying the generator and distribution in the lambda is making them members of the class. Then they have the same lifetime as rand
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); })
{}
The name of this class suggests it will be doing other things. I don't recommend that you expand it, but instead split the generating off into it's own class.
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
{}
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
"undefined behavior which should end with Segmentation Fault" is a non sequitur. By definition, undefined behaviour has no restrictions on what must or should or can happen.
– Caleth
Jul 3 at 8:38