patterncppMinor
std::vector composition with self populating super-powers
Viewed 0 times
stdwithsupercompositionpopulatingpowersvectorself
Problem
I have written a deliberately pretty simple class that wraps a
This is only a hobby project, it is not production code :-) so I'd like to know if there are any ways to improve this design or my approach.
Besides good practices, style and design, two of my biggest doubts are:
-
-
Edit: Forgot to add that, regarding number 2, I'm also a bit curious about the way I'm seeding the engine. Does it looks correct?
Following, the header file:
```
#ifndef algorithmicVec_H
#define algorithmicVec_H
#include
#include
#include
#include
/**
* std::vector composition with pseudo-random number self-populating capabilities
*/
class algorithmicVec {
private:
std::vector vec;
static std::mt19937 gen;
static std::uniform_int_distribution uint_dist99;
/**
* Returns a random uint32_t within the range of 0..99
*/
uint32_t getRandomNumber();
public:
/**
* Seeds static std::mt19937 with the current time in milliseconds since epoch
*/
static void seed();
/**
* Populates the vector with n elements using a std::uniform_int_distribution
* fed with std::mt19937.
*
* Using std::iota() followed by std::shuffle was considered, but not implemented
* mostly because random generated numbers seemed more in
std::vector to basically make it capable of self-populate itself with random generated numbers, simply to be able to test the result of some sorting algorithms that I'm working on. This is only a hobby project, it is not production code :-) so I'd like to know if there are any ways to improve this design or my approach.
Besides good practices, style and design, two of my biggest doubts are:
-
populate(): If I had used std::iota() followed by std::shuffle, as explained on the comments, I believe that the code would be much smaller, simpler and would kind-of have the same result (it wouldn't allow repeated numbers, as it does now).-
std::mt19937 and std::uniform_int_distribution: mostly, if their implementation looks... OK. Looks like the need to explicitly seed the vector is inevitable, but I don't really like it. :-( this would obviously be avoided if I used my std::iota() implementation. I feel like this breaks the class' "super-powers".Edit: Forgot to add that, regarding number 2, I'm also a bit curious about the way I'm seeding the engine. Does it looks correct?
Following, the header file:
```
#ifndef algorithmicVec_H
#define algorithmicVec_H
#include
#include
#include
#include
/**
* std::vector composition with pseudo-random number self-populating capabilities
*/
class algorithmicVec {
private:
std::vector vec;
static std::mt19937 gen;
static std::uniform_int_distribution uint_dist99;
/**
* Returns a random uint32_t within the range of 0..99
*/
uint32_t getRandomNumber();
public:
/**
* Seeds static std::mt19937 with the current time in milliseconds since epoch
*/
static void seed();
/**
* Populates the vector with n elements using a std::uniform_int_distribution
* fed with std::mt19937.
*
* Using std::iota() followed by std::shuffle was considered, but not implemented
* mostly because random generated numbers seemed more in
Solution
I think it is overkill to write an own class. This gives you many issues because you have to reimplement
In the current state I don't see any advantage over having just a function that returns a vector that is filled randomly:
Use it like this:
This approach has the advantage of cleanly separating the functionality of the
Of course this interface looses some flexibility but if you need it then you should write a class that allows to create random vectors and not a vector class that happens to fill itself with random numbers.
Your Approaches
-
Using
-
The seeding of the random number generator can be done during construction which means during static initialization in the implementation file:
About obtaining the seeding from the time I have no experience and cannot help you there.
vector's interface.In the current state I don't see any advantage over having just a function that returns a vector that is filled randomly:
#include
#include
#include
#include
#include
std::vector generateRandomVector(std::size_t size) {
static std::mt19937 gen(
std::chrono::system_clock::now().time_since_epoch()
/ std::chrono::milliseconds(1));
static std::uniform_int_distribution uint_dist99(0, 99);
std::vector result;
result.reserve(size);
std::generate_n(std::back_inserter(result), size,
[&] {return uint_dist99(gen);});
return result;
}Use it like this:
#include
int main() {
for (auto a : generateRandomVector(20)) {
std::cout << a << std::endl;
}
}This approach has the advantage of cleanly separating the functionality of the
vector (which is to store data) from the functionality of the random generation (which just manipulates a vector). Of course this interface looses some flexibility but if you need it then you should write a class that allows to create random vectors and not a vector class that happens to fill itself with random numbers.
Your Approaches
-
Using
iota and shuffle does not really shorten the code of populate and somewhat "obfuscates" the thing that is going on there (so you would have to add additional comments to state what you want to achieve and why you restrict yourself to permutations).-
The seeding of the random number generator can be done during construction which means during static initialization in the implementation file:
std::size_t getSeedFromCurrentTime() {
return std::chrono::system_clock::now().time_since_epoch() /
std::chrono::milliseconds(1);
}
std::mt19937 algorithmicVec::gen(getSeedFromCurrentTime);About obtaining the seeding from the time I have no experience and cannot help you there.
Code Snippets
#include <vector>
#include <random>
#include <chrono>
#include <algorithm>
#include <iterator>
std::vector<uint32_t> generateRandomVector(std::size_t size) {
static std::mt19937 gen(
std::chrono::system_clock::now().time_since_epoch()
/ std::chrono::milliseconds(1));
static std::uniform_int_distribution<uint32_t> uint_dist99(0, 99);
std::vector<uint32_t> result;
result.reserve(size);
std::generate_n(std::back_inserter(result), size,
[&] {return uint_dist99(gen);});
return result;
}#include <iostream>
int main() {
for (auto a : generateRandomVector(20)) {
std::cout << a << std::endl;
}
}std::size_t getSeedFromCurrentTime() {
return std::chrono::system_clock::now().time_since_epoch() /
std::chrono::milliseconds(1);
}
std::mt19937 algorithmicVec::gen(getSeedFromCurrentTime);Context
StackExchange Code Review Q#52213, answer score: 8
Revisions (0)
No revisions yet.