c++ std::Shuffle not random - c++

For fun im making a singleton that is used to shuffle an array. Im trying to shuffle an array in c++ with std::shuffle, but the shuffle produces the same result everytime I run the program.
The code:
// Example program
#include <iostream>
#include <string>
#pragma once
#include <memory>
#include <random>
#include <ctime>
#include <algorithm>
class RandomPicker
{
public:
~RandomPicker();
std::default_random_engine getRandomEngine();
static std::shared_ptr<RandomPicker> getInstance();
private:
std::default_random_engine dre = std::default_random_engine(time(0));
RandomPicker();
static std::shared_ptr<RandomPicker> instance;
};
std::shared_ptr<RandomPicker> RandomPicker::instance = nullptr;
RandomPicker::RandomPicker()
{
}
RandomPicker::~RandomPicker()
{
}
std::default_random_engine RandomPicker::getRandomEngine()
{
return std::default_random_engine();
}
std::shared_ptr<RandomPicker> RandomPicker::getInstance()
{
if (instance == nullptr)
{
instance.reset(new RandomPicker);
}
return instance;
}
int main()
{
std::array<int,5> foo {1,2,3,4,5};
std::shared_ptr<RandomPicker> r = RandomPicker::getInstance();
shuffle (foo.begin(), foo.end(), r->getRandomEngine());
std::cout << "shuffled elements:";
for (int& x: foo) std::cout << ' ' << x;
std::cout << '\n';
}
Link to code showing it:
I thought using
std::default_random_engine dre = std::default_random_engine(time(0));
//notice the time(0)
would get a different result everytime, but the result equals to.
shuffled elements: 3 1 5 4 2
Why is the array not sorted in a different way everytime the program runs?

std::default_random_engine RandomPicker::getRandomEngine()
{
return std::default_random_engine();
}
You getRandomEngine() always returns an engine with default seed.

Your getRandomEngine() should probably return dre:
std::default_random_engine RandomPicker::getRandomEngine()
{
return dre;
}

Related

Insert an element into a range

What is the right implementation of Insert method in the code below?
#include <ranges>
#include <vector>
#include <set>
template <std::ranges::range Range>
class Processor
{
public:
using T = std::ranges::range_value_t<Range>;
void Insert(Range range, T val)
{
//add val into range
}
};
int main()
{
std::vector<int> v;
Processor<std::vector<int>> p;
p.Insert(v, 5);
std::set<int> set;
Processor<std::set<int>> p1;
p.Insert(set, 5);
return 0;
}
Is it possible to insert to vector and set with the same code? (insertion into vector is probably push_back)
Is it possible to insert to vector and set with the same code? (insertion into vector is probably push_back)
If you want to call the same function for set and vector you could try this soultion using templates, constexpr if and std::same_as.
example:
#include <ios>
#include <iostream>
#include <set>
#include <type_traits>
#include <vector>
template <typename Range, typename T>
void
insertInSetOrVector (Range &range, T const &t)
{
if constexpr (std::same_as<std::vector<T>, Range>)
{
range.push_back (t);
}
else if constexpr (std::same_as<std::set<T>, Range>)
{
range.insert (t);
}
}
int
main ()
{
auto vec = std::vector<int>{};
insertInSetOrVector (vec, 42);
auto set = std::set<int>{};
insertInSetOrVector (set, 42);
std::cout << "vector: " << vec.at (0) << std::endl;
std::cout << std::boolalpha << "set has 42: " << (set.count (42) == 1) << std::endl;
return 0;
}
which prints:
vector: 42
set has 42: true
edit: thanks for the suggestion (set.count (42) == 1) is more accurate.

How to change values of array at initialization in C++?

I want an array that have new attributed values if the value is x.
I can do that in PHP with that code:
$test = array(1=>55, 2=>66);
on above code if test[0] = 1, the new value of test[0] is going to be 55.
I want to do that in C++.
Normal C++ arrays do not have keys. There are always 0-indexed.
But we have std::map which is what PHP also use internally for key-based containers.
https://en.cppreference.com/w/cpp/container/map
You can make your own attributed values class in C++, so it has that behavior.
You can make it so the behavior is hard coded into the class. Or if you want to get fancier you can make the class having a value mapping passed in.
Here's an example with the value mapping passed into the class.
#include <cstddef>
#include <iostream>
#include <map>
#include <stdexcept>
#include <vector>
using sad_panda = std::logic_error;
using std::cout;
using std::map;
using std::size_t;
using std::vector;
namespace {
class AttributedValues {
vector<int> v;
map<int, int> attr_to_value;
public:
AttributedValues(map<int, int> mapping);
void set(size_t index, int value);
int operator[](size_t index) const;
};
AttributedValues::AttributedValues(map<int, int> mapping)
: attr_to_value{mapping}
{ }
void AttributedValues::set(size_t index, int value) {
if (index >= v.size()) {
v.resize(index+1);
}
auto iter = attr_to_value.find(value);
if (iter != attr_to_value.end()) {
value = iter->second;
}
v[index] = value;
}
int AttributedValues::operator[](size_t index) const {
if (index >= v.size()) {
throw sad_panda("AttributedValues::operator[] index out of range");
}
return v[index];
}
} // anon
int main() {
auto test = AttributedValues{{{1, 55}, {2, 66}}};
test.set(0, 1);
test.set(10, 2);
cout << test[0] << "\n";
cout << test[10] << "\n";
}

Generating a map of strings to std::list of pointers in c++

I am trying to achieve the creation of such a map. The following code attempts to do this
#include <list>
#include <map>
#include <string>
class IntWithString {
private:
int a;
std::string s;
public:
IntWithString(int a, std::string s) : a(a), s(s) {}
std::string getString() { return s; }
int getInt() { return a; }
};
namespace {
std::map<std::string, std::list<IntWithString *> > m;
}
void appendMap(IntWithString *a) {
auto it = m.find(a->getString());
if (it != m.end()) {
m[a->getString()].push_back(a);
} else {
std::list<IntWithString *> l;
l.push_back(a);
m[a->getString()] = l;
}
}
int main() {
IntWithString a(10, "ten");
IntWithString b(11, "ten");
appendMap(&a);
appendMap(&b);
return 0;
}
However when looking at the map m with the debugger I am getting a map that maps "ten" to a list of size 0. What I would like is a list of size 2.
I am not sure what you mean. If I do:
std::cout << m.size() << ", " << m["ten"].size() << std::endl;
I get this output:
1, 2
which is a map with one key ("ten"), and two values for that key (10 and 11), as expected.
Live demo
PS: Storing pointers in a container like this is a bit uncommon in C++. If you really want to do this though, consider to use Smart Pointers.

Cannot Return Values When Passing Function by Reference To TBB Task

I'm getting my feet wet with Intel TBB and am trying to figure out why I cannot populate a vector passed in by reference to a TBB Task when I also pass in a function by reference.
Here is the code:
// tbbTesting.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include "tbb/task.h"
#include <functional>
#include <iostream>
#include <random>
#define NUM_POINTS 10
void myFunc(std::vector<double>& numbers)
{
std::mt19937_64 gen;
std::uniform_real_distribution<double> dis(0.0, 1000.0);
for (size_t i = 0; i < NUM_POINTS; i++)
{
auto val = dis(gen);
std::cout << val << std::endl; //proper values generated
numbers.push_back(val); //why is this failing?
}
std::cout << std::endl;
for (auto i : numbers)
{
std::cout << numbers[i] << std::endl; //garbage values
}
}
class TASK_generateRandomNumbers : public tbb::task
{
public:
TASK_generateRandomNumbers(std::function<void(std::vector<double>&)>& fnc,
std::vector<double>& nums) : _fnc(fnc), _numbers(nums) {}
~TASK_generateRandomNumbers() {};
tbb::task* execute()
{
_fnc(_numbers);
return nullptr;
}
private:
std::function<void(std::vector<double>&)>& _fnc;
std::vector<double>& _numbers;
};
class Manager
{
public:
Manager() { _numbers.reserve(NUM_POINTS); }
~Manager() {}
void GenerateNumbers()
{
_fnc = std::bind(&myFunc, _numbers);
TASK_generateRandomNumbers* t = new(tbb::task::allocate_root())
TASK_generateRandomNumbers(_fnc, _numbers);
tbb::task::spawn_root_and_wait(*t);
}
auto GetNumbers() const { return _numbers; }
private:
std::function<void(std::vector<double>&)> _fnc;
std::vector<double> _numbers;
};
int main()
{
Manager mgr;
mgr.GenerateNumbers();
auto numbers = mgr.GetNumbers(); //returns empty
}
When the execute method performs the operation, I can get values when passing the vector by reference.
When the execute method has to call a function, I get garbage data printed to the console (push_back failing?) and I get an empty container on return.
Can anyone see what I'm missing? Thanks.
I have found a couple of bugs that have nothing to do with tbb.
1) Your myFunc is using range for incorrectly. It does not return an index but each value directly in the vector in turn. Your code is casting each double to an int and using that as index into the array which is why you are gettign garbage.
2) When you use std::bind to create a functor the arguments are copied by value. If you want to pass in a reference then you need to use std::ref to wrap the argument.
If you are using c++11 then you might want to consider using a lambda rather than bind.
I've written a small program using your myFunc in different ways: with and without using std::ref and also a lambda example. You should see that it generates the same numbers 3 times but when it tries to print out v1 it wont contain anything because the generated values were placed in a copy.
#include <vector>
#include <random>
#include <iostream>
#include <functional>
constexpr size_t NUM_POINTS = 10;
void myFunc(std::vector<double>& numbers)
{
std::mt19937_64 gen;
std::uniform_real_distribution<double> dis(0.0, 1000.0);
for (size_t i = 0; i < NUM_POINTS; i++)
{
auto val = dis(gen);
std::cout << val << std::endl; //proper values generated
numbers.push_back(val); //why is this failing? it's not
}
std::cout << std::endl;
}
void printNumbers(std::vector<double>const& numbers)
{
for (auto number : numbers)
{
std::cout << number << std::endl;
}
std::cout << std::endl;
}
int main()
{
std::cout << "generating v1" << std::endl;
std::vector<double> v1;
auto f1 = std::bind(&myFunc, v1);
f1();
printNumbers(v1);
std::cout << "generating v2" << std::endl;
std::vector<double> v2;
auto f2= std::bind(&myFunc, std::ref(v2));
f2();
printNumbers(v2);
std::cout << "generating v3" << std::endl;
std::vector<double> v3;
auto f3 = [&v3]() { myFunc(v3); }; //using a lambda
f3();
printNumbers(v3);
return 0;
}

Proper usage of std::atomic, pre increment value as function param

I have code where I need unique id (packet id for some protocol). So I used std::atomic<int>. After reading documentation I was confused because it stated that increment is done in this way. fetch_add(1)+1
I understand that value inside fetch_add is incremented atomically but I get pre-increment value +1 outside atomic operation. What I would guess is not atomic.
Can I use some_func(++atomic_value)?
I wrote simple code to check if it works. And it works but I don't understand why.
#include<iostream>
#include <atomic>
#include <thread>
#include <vector>
#include <random>
#include <mutex>
#include <algorithm>
std::atomic<int> Index = 0;
//int Index = 0; // non atomic Index. It will generate duplicities
std::vector<int> Numbers;
std::mutex Mutex;
std::default_random_engine Generator;
std::uniform_int_distribution<int> Distribution(5, 10);
void func(int Value)
{
std::lock_guard<std::mutex> Guard(Mutex);
Numbers.push_back(Value);
}
void ThreadProc()
{
Sleep(Distribution(Generator));
func(++Index); // is this proper usage of std::atomic?
}
int main()
{
const int ThreadCount = 1000;
std::vector<std::thread> Threads;
for ( int i = 0; i < ThreadCount; i++ )
{
Threads.push_back(std::thread(ThreadProc));
}
for_each(Threads.begin(), Threads.end(), [](std::thread& t) { t.join(); });
std::sort(Numbers.begin(), Numbers.end());
auto End = std::unique(Numbers.begin(), Numbers.end());
if ( Numbers.end() == End )
{
std::cout << "No duplicites found." << std::endl;
}
else
{
std::cout << "Duplicites found ! - " << Numbers.end() - End << std::endl;
for_each(End, Numbers.end(), [](int n) { std::cout << n << ", "; });
}
return 0;
}
Off-topic question: When I defined Index as non atomic I get duplicities but only from end of range. Numbers are always 900+. Why it is so?