I have written a deliberately pretty simple class that wraps a 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 usedstd::iota()
followed bystd::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
andstd::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 mystd::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 <vector>
#include <random>
#include <chrono>
#include <cstdint>
/**
* std::vector composition with pseudo-random number self-populating capabilities
*/
class algorithmicVec {
private:
std::vector<uint32_t> vec;
static std::mt19937 gen;
static std::uniform_int_distribution<uint32_t> 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 interesting at the time,
* even to observe the result of the tested algorithms with possible repeated numbers.
*/
void populate (int sz);
/**
* Returns item at position pos
*/
uint32_t at(int pos);
/**
* Returns an iterator to the first item of the vector
*/
std::vector<uint32_t>::iterator begin();
/**
* Returns an iterator past-to-the-end of the vector
*/
std::vector<uint32_t>::iterator end();
};
#endif
The implementation file:
#include "algorithmicVec.hpp"
std::mt19937 algorithmicVec::gen;
std::uniform_int_distribution<uint32_t> algorithmicVec::uint_dist99(0, 99);
void algorithmicVec::seed() {
unsigned long seed = std::chrono::system_clock::now().time_since_epoch() /
std::chrono::milliseconds(1);
gen.seed(seed);
}
void algorithmicVec::populate (int sz) {
for (int i = 0; i < sz; ++i) {
vec.push_back(getRandomNumber());
}
}
uint32_t algorithmicVec::getRandomNumber() {
return uint_dist99(gen);
}
uint32_t algorithmicVec::at(int pos) {
return vec.at(pos);
}
std::vector<uint32_t>::iterator algorithmicVec::begin() {
return vec.begin();
}
std::vector<uint32_t>::iterator algorithmicVec::end() {
return vec.end();
}
A minimal test case:
#include <iostream>
#include "algorithmicVec.cpp"
int main() {
algorithmicVec::seed();
algorithmicVec myVec;
myVec.populate(10); // populates myVec with 10 random numbers
for (auto a: myVec) {
std::cout << a << std::endl;
}
}