I have a class dieClass
to represent a six-sided die, and I use <random>
to set the number. Here is the header file die.h
:
#include <random>
#include <iostream>
class dieClass
{
public:
dieClass();
int getNum() const { return num; }
private:
int num;
static std::uniform_int_distribution<int> distribution;
};
and here is the implementation file die.cpp
:
#include "die.h"
dieClass::dieClass()
{
static std::random_device rdevice{};
static std::default_random_engine generator{rdevice()};
num = distribution(generator);
}
std::uniform_int_distribution<int> dieClass::distribution{1, 6};
Question: If I call dieClass dice[5]
, have I created five default_random_engines
, or just one because it is static? Basically, what would be the most efficient way to construct millions of dice? Can I declare generator
outside of the constructor, like I did for distribution
? I don't fully understand what private and static do.
EDIT: Rearranging things like this seems to achieve what I want, although it may not be best practice. I pulled all random-number-generating code from the class and stuck it in the implementation file. Now I can call generator
from a function roll
.
dieClass.h
#include <iostream>
class dieClass
{
public:
die();
void roll();
int getNum() const { return num; }
private:
int num;
};
dieClass.cpp
#include <random>
#include "die.hpp"
std::random_device rdevice{};
std::default_random_engine generator{rdevice()};
std::uniform_int_distribution<int> distribution{1, 6};
dieClass::dieClass()
{
num = distribution(generator);
}
void dieClass::roll()
{
num = distribution(generator);
}
If you are going to have millions of dice I prefer your second example. It will be more efficient to have one random generator. However, instead of a global random number generator for your dice you can encapsulate it inside a class.
Like static variables you should avoid the use of globals as much as possible. It is possible to inject a reference or pointer to this new generator class to your dieClass
. Just change the constructor to accept it. Whenever you want to generate a new number just call a method of the new class.
Here's an example:
#include <random>
#include <iostream>
class RandomNumberGenerator
{
public:
RandomNumberGenerator() : mRd(), mGen(mRd()), mDis(1, 6) {}
~RandomNumberGenerator() = default;
inline int Generate() { return mDis(mGen); }
private:
std::random_device mRd;
std::mt19937 mGen;
std::uniform_int_distribution<int> mDis;
};
class dieClass
{
public:
dieClass(RandomNumberGenerator &gen) : mGenerator(gen), num(gen.Generate()) {}
int getNum() const { return num; }
void roll() { num = mGenerator.Generate(); }
private:
RandomNumberGenerator &mGenerator; //store as reference to avoid copying
int num;
};
This way it's the responsibility of the RandomNumberGenerator
class to generate the randome number, not the dieClass
class.
Working version here.