Handling C++11 <random> - separate class and *.cpp file

Hello everyone,
I wanted to ask for an advice about how to create .cpp file (new class) that will handle all the random number generators (<random> library) that main could possibly access. When I looked for a way how to implement random generators the examples were always in the main function or in a class in the main.cpp (with no header file and the generator was not seeded as I imagine it should be = only once in a program).

Questions follows after this malfunction code.

main.cpp
1
2
3
4
5
6
7
#include "randomizer.h"

int main()
{
   Randomizer randObject(0, 10, 125);       //Set bounds and seed generator
   int mainVar = randObject.getRandInt();   //Store newly generated random number for future work
}

randomizer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <random>       //All random generators
#include <ctime>        //std::time

class Randomizer
{
   public:
      Randomizer(int boundMin, 
                 int bountMax,
                 int seed = std::time(0));
      //~Randomizer();         //Destructor not required?
      
      int getRandInt();
      int getSeed();
   private:
      int seed_;              //Store seed value if needed later
      //Here should be probably declaration of generator/distribution, but how?
}

randomizer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "randomizer.h"

Randomizer::Randomizer(int boundMin, int boundMax, int seed)
   : seed_(seed)
{
   std::default_random_engine defGen(seed_);
   std::uniform_int_distribution<int> randInt(boundMin, boundMax);
}

int Randomizer::getRandInt()
{
   return randInt(defGen);    //Doesn't work
   //randInt probably went out of bounds at the end of Randomizer()
}

int Randomizer::getSeed()
{
   return seed_;
}


Now when I tried to change function getRandInt to:
1
2
3
4
5
6
int Randomizer::getRandInt()
{
   std::uniform_int_distribution<int> randInt(boundMin_, boundMax_);
   //boundMin_, boundMax_ were declared as private class variables earlier
   return randInt(defGen);    //Doesn't work - seed is not changing rand output
}


1) So I think that I should somehow declare these generators and distribution in the header file. But I have no idea how. Is it like declaring int a;?
I tried writing std::default_random_engine defGen; into the header file which only silenced compiler's errors but defGen wasn't seeded.
I have seen some examples using auto a = randInt(defGen); (or maybe with the use of auto a = std::bind.... But what does auto represent? I can't use it in the header file.

2) Can I ensure that the randObject is seeded only once? If for examle I need randObject2 with different boundMax, can I still use the same defGen which was seeded the first time? That should ensure better "randomness" through the program, shouldn't it?

3) Is there better way (and easy too) to "interface" random number generators? The class in the end should provide "get" function to acces int, double, bool, signed/unsigned... or some other specialities like random prime numbers, etc.

If it is anyhow related I am using Code::Blocks IDE with GCC compiler (4.7.1)

I would be grateful for any help :-)
Last edited on
Hello,
since I got no response in Beginners forum I was hoping that someone in General C++ Programming could help me with my problem.

Thanks.
> Destructor not required?
¿do you need to release any resource?

> randInt probably went out of bounds at the end of Randomizer()
yes.

> Doesn't work
¡what a helpful error message!

> Doesn't work - seed is not changing rand output
¿where and how did you declared `defGen'?
¿how are you testing the output?

> I tried writing std::default_random_engine defGen; into the header file which only silenced compiler's errors
> but defGen wasn't seeded.
Because you are using the default constructor of `default_random_engine', it is using a default seed.
Call the proper constructor using the initialization list, like you did with `seed_'

> auto a = randInt(defGen);
> But what does auto represent?
`a' would have the type of whatever the expression on the right side is.
Considering line 7, `a' would be an int
In the case of `std::bind' it would return a function, but the prototype of that function would depend on the bind construction.

> Can I ensure that the randObject is seeded only once?
> If for examle I need randObject2 with different boundMax,
> can I still use the same defGen which was seeded the first time?
you can make all the `Randomizer' objects to use the same `engine'
you can make all the `Randomizer' objects to have their own `engine'
you can make that some `Randomizer' objects share one `engine'
It depends on how do you declare the engine.

Hello and thank you for a reply,
that confirmed some of my thoughts.

I have rewritten the program so:
randomizer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <random>       //All random generators
#include <ctime>        //std::time

class Randomizer
{
   public:
      Randomizer(int boundMin, 
                 int bountMax,
                 int seed = std::time(0));
      
      int getRandInt();
   private:
      int seed_;              //Store seed value if needed later
      std::default_random_engine defGen_;
      std::uniform_int_distribution<int> randInt_;
}


randomizer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
#include "randomizer.h"

Randomizer::Randomizer(int boundMin, int boundMax, int seed)
   : seed_(seed),
     defGen_(seed_),
     randInt_(boundMin, boundMax)
{
}

int Randomizer::getRandInt()
    return randInt_(defGen_);
}


And now it works as I wanted.
I just hope there is no hidden risk for my program.
I think that you've got some typos.
Missing semicolon on line 16 randomizer.h
Missing opening brace one line 10 randomizer.cpp

Suppose this client code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(){
	Randomizer a(1,6,42);
	for(int K=0; K<5; ++K)
		std::cout << a.getRandInt() << ' ';
	std::cout << '\n';

	Randomizer b(a); //copying the engine
	for(int K=0; K<5; ++K)
		std::cout << a.getRandInt() << ' ';
	std::cout << '\n';
	for(int K=0; K<5; ++K)
		std::cout << b.getRandInt() << ' '; //same sequence
	std::cout << '\n';
}
1 4 5 2 3 
2 6 4 4 2 
2 6 4 4 2 
¿is that the behaviour that you wanted?
Last edited on
Topic archived. No new replies allowed.