Home > database >  Inheritance and random number generation in const member function
Inheritance and random number generation in const member function

Time:03-12

I have the following class inheritance structure

#include <random>
class ABC{
protected:
    std::mt19937_64 rng;
    double a();//calls random correction
    virtual double random_correction() const=0;
public:
    double x;
    explicit ABC(const double x0) :
        rng(std::random_device{}()), x(x0){}
    ABC(const ABC& other)=default;
    ABC& operator=(const ABC& other)=default;
    ABC(ABC&& other) noexcept = default;
    ABC& operator=(ABC&& other) noexcept = default ;
    virtual ~ABC()=default;
    virtual void update(const int step_number)=0;//calls a and uses rng
    
};
             

class D1 : public ABC{
private:
    double y;
    double random_correction() const override {return 0;};
public:
    D1(const double x0, const double y0):
    ABC(x0), y(y0){}
    D1(const D1& other)=default;
    D1& operator=(const D1& other)=default;
    D1(D1&& other) noexcept = default;
    D1& operator=(D1&& other) noexcept = default ;
    ~D1() override=default;
    void update(const int step_number) override;
};

class D2 : public D1{
private:
    double noise;
    double random_correction() const override {
    static std::uniform_real_distribution<> u{-noise, noise};
    return u(rng); //error here     
    };
public:
    D2(const double x0, const double y0, const double na):
    D1(x0,y0), noise(na) {}
    D2(const D2& other)=default;
    D2& operator=(const D2& other)=default;
    D2(D2&& other) noexcept = default;
    D2& operator=(D2&& other) noexcept = default ;
    ~D2() override=default;
};

In the definition of random_correction of D2 I get the following error: "in instantiation of function template specialization 'std::uniform_real_distribution::operator()<const std::mersenne_twister_engine<unsigned long, 64, 312, 156, 31, 13043109905998158313, 29, 6148914691236517205, 17, 8202884508482404352, 37, 18444473444759240704, 43, 6364136223846793005> >' requested here" . If I erase the const qualifier in all the declaration the error disappear. Why? Doesn't a const qualifier in a member function mean that no member of the class is going to be modified?

As a workaround I thought I could modify the class D2 in this way

class D2 : public D1{
private:
    double noise;
    std::uniform_real_distribution<> u;
    double random_correction() const override {
    return u(rng); //error always here      
    };
public:
    D2(const double x0, const double y0, const double na):
    D1(x0,y0), noise(na) {u.param(std::uniform_real_distribution<>::param_type{-noise, noise});}
    D2(const D2& other)=default;
    D2& operator=(const D2& other)=default;
    D2(D2&& other) noexcept = default;
    D2& operator=(D2&& other) noexcept = default ;
    ~D2() override=default;
};

However now I get the error: "no matching function for call to object of type 'const std::uniform_real_distribution<>'". I suppose because generating a random number changes the state of u (and maybe of rng as well). Is this correct? Is it convenient to have a distribution as a member?

P.S. Please, if there is any design error or inefficiency point it out to me.

CodePudding user response:

Generating random number doesn't change the state of u. It's state is just what range of values to be generated.

But it does change the state of rng. Pseudo-random number generators are usually deterministic meaning that rng() is determined by the current state and the state will change upon evaluation so next time a different value will be produced.

To fix the compilation issue, you can either drop the const declaration of the function or you can declare rng to be mutable. It will still bear certain problems like "accessing the class instance concurrently will cause data races". So you might consider rethinking the design.

RNG engines can benefit from thread_local keyword... but you'll need to design it in a way so it won't cause performance issues which can be a bit tricky.

  • Related