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 に初期化する方法を理解できれば、これはうまくいくと思います。この static 値を 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

この問題は、 を使用する際の問題の 1 つですrand()。C++11 では、<random>この問題やその他の問題を解決するライブラリが導入されました。

新しい APIの単一のグローバル (またはスレッドごとrand()の) 状態を持つ代わりに、RNG の状態を値のセマンティクスを持つオブジェクトにカプセル化することで、RNG の状態を明示的に制御できます。

メンバー変数として状態を維持するか、すべてのインスタンスで 1 つを共有する場合は静的メンバーとして維持するか、その他の用途に適したものを維持できます。

#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()

(上記では、<random>均一な初期化、および非静的メンバーのクラス内初期化以外に、いくつかの C++11 機能を使用しています。)

于 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_onceやメンバーboost::call_onceなどの OS の機能を使用してstatic、シードを 1 回だけ実行します。

于 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 に答える