6

我正在研究一个rand()在构造函数中使用 a 的 C++ 类。我真的很想让这门课在几乎所有方面都能照顾好自己,但我不知道在哪里播种rand()

如果我rand()在构造函数中播种,则每次构造我的对象类型的新实例时都会播种。因此,如果我要按顺序创建 3 个对象,它们都将在同一秒内创建,因此具有相同的种子rand(),为对象的 3 个实例中的每一个实例生成完全相同的数据。

我想rand()在类代码中播种,而不是在创建对象之前在程序的主函数中进行。我想过做一个static bool seeded;变量来表示是否rand()已经播种,但我不确定如何在创建类时将其初始化为 false。

我的想法是这样的

myConstructor(){
    if(!seeded){
        srand(time(NULL));
        seeded = true;
    }

    myVariable = rand()%maxVal;
}

我认为如果我能在程序开始时弄清楚如何将静态值初始化为 false 一次,这将起作用。我的理解是,如果这个静态值是静态的,那么将这个静态值更改为 true 将跨越对象的所有实例,因此只会在第一次创建该对象类型时执行种子函数。

4

5 回答 5

6

我认为如果我能在程序开始时弄清楚如何将静态值初始化为 false 一次,这将起作用。

// my_class.h
class my_class {
public:
  // ...
private:
  static bool seeded;
};

// my_class.cpp
bool my_class::seeded = false;

确保seeded在实现文件中定义。否则,包含您的标头的每个文件都将获得自己的静态成员定义,并且还可能导致链接器问题,因为它可以被多次定义。

附带说明一下,如果静态成员是 const 整数类型,则可以在声明时对其进行分配。

另一种选择是这个,我个人更喜欢它来完成这项任务:

my_class::my_class()         
{
    static bool seeded = false;
    if(!seeded) {
        srand(time(NULL));
        seeded = true;
    }

    myVariable = rand() % maxVal;
}
于 2012-11-04T02:28:13.483 回答
5

此问题是使用rand(). C++11 引入了<random>解决这个问题和其他问题的库。

新 API没有单一的全局(或每个线程)状态,而是rand()通过将 RNG 封装在具有值语义的对象中来显式控制 RNG 的状态。

您可以将状态维护为成员变量,或者如果您希望所有实例共享一个,或者任何其他对您的使用有意义的情况,则可以将其维护为静态成员。

#include <random> // for mt19937, uniform_int_distribution
#include <iostream>

std::mt19937 seeded_engine() {
    std::random_device r;
    std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
    return std::mt19937(seed);
}

struct C {
    // Hold RNG state as a member variable
    std::mt19937 eng = seeded_engine();
    
    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';
}

有关. _ _seeded_engine()

(除此之外,上面还使用了一些 C++11 特性<random>;统一初始化和非静态成员的类内初始化。)

于 2012-11-04T02:55:58.927 回答
2

使用仅初始化一次的静态变量功能:

static bool seed()
{
  srand(time(NULL));
  return true;
}
myConstructor(){
  static bool seeded = seed();
  myVariable = rand()%maxVal;
}
于 2012-11-04T02:32:21.727 回答
1

该问题类似于单例实例化的问题。使用你的操作系统的一个特性,比如pthread_onceorboost::call_once和一个static成员来执行一次种子。

于 2012-11-04T02:28:29.693 回答
0

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);
}
于 2016-03-25T06:25:04.430 回答