Я работаю над классом C ++, который использует rand()
в конструкторе. Мне бы очень хотелось, чтобы этот класс позаботился о себе почти во всех отношениях, но я не уверен, где посеять rand()
,
Если я семя rand()
в конструктор он будет добавляться каждый раз, когда создается новый экземпляр типа моего объекта. Поэтому, если бы я создал 3 объекта в последовательности, все они были бы созданы в одну секунду и, следовательно, имели бы одинаковое начальное число для rand()
создавая одинаковые данные для каждого из 3 экземпляров объекта.
Я хотел бы посеять rand()
в коде класса, вместо того, чтобы делать это в основной функции моей программы перед созданием объекта. Я думал сделать static bool seeded;
переменная, которая показывает, является ли rand()
был посеян, но я не совсем уверен, как инициализировать его как false при создании класса.
Моя идея звучит примерно так
myConstructor(){
if(!seeded){
srand(time(NULL));
seeded = true;
}
myVariable = rand()%maxVal;
}
Я думаю, что это сработало бы, если бы я мог просто выяснить, как инициализировать статическое значение в false один раз в начале программы. Насколько я понимаю, изменение этого статического значения на true будет распространяться на все экземпляры объекта, если оно будет статическим, и, следовательно, будет выполнять начальную функцию только при первом создании этого типа объекта.
Я думаю, что это сработало бы, если бы я мог просто выяснить, как инициализировать статическое значение в false один раз в начале программы.
// my_class.h
class my_class {
public:
// ...
private:
static bool seeded;
};
// my_class.cpp
bool my_class::seeded = false;
Убедитесь, что определили seeded
в файле реализации. В противном случае каждый файл, содержащий ваш заголовок, получит свое собственное определение статического члена, что также может вызвать проблемы с компоновщиком, так как он может быть определен более одного раза.
Напомним, что если статический член имел константный целочисленный тип, вы можете назначить его в точке объявления.
Другим вариантом было бы это, и лично я предпочел бы это для этой задачи:
my_class::my_class()
{
static bool seeded = false;
if(!seeded) {
srand(time(NULL));
seeded = true;
}
myVariable = rand() % maxVal;
}
Эта проблема является одной из проблем использования rand()
, C ++ 11 представил <random>
библиотека, которая решает эту и другие проблемы.
Вместо того, чтобы иметь единственное глобальное (или на поток) состояние для rand()
Новый API дает вам явный контроль над состоянием ГСЧ, инкапсулируя его в объект с семантикой значений.
Вы можете поддерживать состояние как переменную-член или как статический член, если хотите, чтобы все экземпляры разделяли его, или что-либо еще, что имеет смысл для вашего использования.
#include <random> // for mt19937, uniform_int_distribution
#include <chrono> // for high_resolution_clock
#include <iostream>
struct C {
// Hold RNG state as a member variable
std::mt19937 eng{std::chrono::high_resolution_clock::now().time_since_epoch().count()};
int foo() {
// use the member variable to generate random numbers in a member function.
return std::uniform_int_distribution<>(1,10)(eng);
}
};
int main() {
C c, d;
std::cout << c.foo() << '\n';
std::cout << d.foo() << '\n';
}
(Выше используется несколько функций C ++ 11, кроме <random>
; <chrono>
библиотека для времени, равномерной инициализации и инициализации в классе для нестатических элементов.)
Используйте функцию статической переменной, которая инициализируется только один раз:
static bool seed()
{
srand(time(NULL));
return true;
}
myConstructor(){
static bool seeded = seed();
myVariable = rand()%maxVal;
}
Проблема похожа на проблему синглтон-инстанцирования. Используйте функцию вашей ОС, например pthread_once
или же boost::call_once
и static
член для выполнения семян один и только один раз.
У bames53 был отличный ответ. Теперь, чтобы сделать все это в отдельную целочисленную функцию:
int generateRandom(int min, int max) {
std::mt19937 eng{std::chrono::high_resolution_clock::now().time_since_epoch().count()};
return std::uniform_int_distribution<>(min,max)(eng);
}