I'm trying to write a simple struct around an std random number generator. According to the compiler I can initialize this class but when I try to use the function it gives the following error:
Error C2280 'RandNormGen::RandNormGen(const RandNormGen &)': attempting to reference a deleted function
I don't fully understand what this means or what to do about it, but I think I narrowed it down to having something to do with the std::random_device rd;
here is my struct:
struct RandNormGen {
std::random_device rd;
std::mt19937 gen;
std::normal_distribution<float> normalDist;
RandNormGen() {
gen = std::mt19937(rd());
normalDist = std::normal_distribution<float>(0, 1);
}
float randFloat(float sigma, float mean = 0) {
float r = normalDist(gen) * sigma mean;
return r;
}
};
any help or insight would be appreciated!
CodePudding user response:
std::random_device
is not copyable or movable. So your class also cannot be copied or moved.
However, there isn't really any point to keeping the std::random_device
instance around. You (hopefully) use it only to seed the actual random number generator. So remove it from the struct and instead in the constructor:
gen = std::mt19937(std::random_device{}());
or skip the constructor entirely and use default member initializers, since your default constructor does nothing but initialize the members:
struct RandNormGen {
std::mt19937 gen{std::random_device{}()};
std::normal_distribution<float> normalDist;
float randFloat(float sigma, float mean = 0) {
float r = normalDist(gen) * sigma mean;
return r;
}
};
(The default constructor of std::normal_distribution
already initializes to distribution parameters to 0
and 1
but std::normal_distribution<float> normalDist{0, 1};
would work as well.)
Be aware however of what you are doing that causes the requirement for the copy constructor in the first place.
If you actually copy rather than move the class object, you will end up with two instances of the class with the same state of the random number generator, meaning that the random numbers generated in the copy will not be different from those generated in the original.
If that is not the behavior you want, you can delete the copy constructor explicitly so that only moves will be allowed:
RandNormGen() = default;
RandNormGen(const RandNormGen&) = delete;
RandNormGen(RandNormGen&&) = default;
RandNormGen& operator=(const RandNormGen&) = delete;
RandNormGen& operator=(RandNormGen&&) = default;
or you can define a copy constructor and assignment operator with the intended semantics (e.g. reseeding the generator).
Even more generally, consider moving the random number generator out of the class. There is usually not really any point in having a random generator for each object. Usually having a generator per thread in the program is sufficient.