4
\$\begingroup\$

With the following interface in mind

EasyRandom<unsigned int> prng(a, b);
auto x = prng();   // scalar
auto v = prng(10); // vector

I wrote the following class:

// https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
template <typename T = unsigned int>
class EasyRandom
{
private:
  std::random_device rd;
  std::unique_ptr<std::mt19937> gen;
  std::unique_ptr<std::uniform_int_distribution<T>> dist;

public:
  EasyRandom(T a, T b)
  {
    gen = std::make_unique<std::mt19937>(rd());
    dist = std::make_unique<std::uniform_int_distribution<T>>(a, b);
  }

  T operator()() { return (*dist)(*gen); }

  std::vector<T> operator()(size_t n)
  {
    std::vector<T> v;
    for (; n > 0; v.push_back(operator()()), --n);
    return v;
  }
};

I also have a few specific questions:

  1. Is there a way to instantiate EasyRandom without the use of pointers?
  2. Is it possible to change operator()(size_t n) to return any user-specified SequenceContainer (e.g. vector, list, deque) instead of hard-coding it to a particular implementation (e.g. std::vector)?
\$\endgroup\$
  • \$\begingroup\$ As @1201ProgramAlarm already pointed out the second part of your question is off-topic and could lead to your entire question being closed. Please revise your question if you want to prevent this. \$\endgroup\$ – yuri Jun 18 '19 at 7:57
  • 1
    \$\begingroup\$ Adding a non-working implementation does not make the question on topic for Code Review. We require the code be working. For more information, see the help center. I have rolled back the edit you made to avoid incurring closevotes. \$\endgroup\$ – Vogel612 Jun 18 '19 at 10:55
  • 1
    \$\begingroup\$ Some notes on what you've got so far: 1. Keeping the instance of std::random_device that you use only once wastes space. 2. Instantiating one std::unique_ptr<std::mt19937> per distribution wastes a lot of space and makes creating distributions really slow. You typically want exactly one generator per thread that is generating random numbers, so make the generator [static] thread_local. \$\endgroup\$ – Ted Lyngmo Jun 19 '19 at 19:31
3
\$\begingroup\$

gen and dist don't need to be pointers. Just declare them as members, and use the member initializer list in the constructor to initialize them.

std::random_device rd;
std::mt19937 gen;
std::uniform_int_distribution<T> dist;

EasyRandom(T a, T b): gen(rd()), dist(a, b) {
}

In the operator() that returns a vector, you can reserve space for the vector to avoid memory reallocations during the insertions (v.reserve(n)). While not an issue with ints, if you use emplace_back rather than push_back that can avoid potential extra copies of a value for non-simple types.

The second question is off topic (code not implemented).

\$\endgroup\$
  • \$\begingroup\$ Added implementation for second question. Thank you for your feedback so far. \$\endgroup\$ – Sparkler Jun 18 '19 at 5:28

Not the answer you're looking for? Browse other questions tagged or ask your own question.