std::generate() で生成した乱数が毎回同じになるのはなぜ?

投稿者: Anonymous

C++で乱数の配列を生成しようとしています。

以下のようなコードを書いてみたのですが、配列の内容が毎回同じになってしまいます。generate_array() の呼び出しで rng の内部状態は更新されるはずだと思うのですが、実際にはそうなっていないように見えます。なぜこのような挙動になるのでしょうか?

#include <algorithm>
#include <functional>
#include <random>
#include <iostream>

using namespace std;

default_random_engine rng;

void print_array(const int* ary, size_t n)
{
    for(size_t i = 0; i < n-1; ++i)
        cout << ary[i] << (i==n-1 ? "" : " ");
    cout << "n";
}

void generate_array(int* ary, size_t n)
{
    uniform_int_distribution<int> dist;
    auto gen = bind(dist,rng);
    generate(ary, ary+n, gen);
}

int main()
{
    random_device rd;
    rng.seed(rd());

    constexpr int N = 10;
    int ary[N];

    fill(ary, ary+N, 0);
    print_array(ary, N);

    generate_array(ary, N);
    print_array(ary, N);
    generate_array(ary, N);
    print_array(ary, N);

    return 0;
}

wandbox上での実行結果を示します:
https://wandbox.org/permlink/RVHGTKCvVtfmS04F

なお、bind(dist,rng) の直前に dist(rng) の呼び出しを入れるとなぜか意図した通りの動作になります:
https://wandbox.org/permlink/LwQjAjxhDJBqDvuI

解決

std::bindはオブジェクトをコピーします。状態をコピーされた乱数生成器は同じ乱数を生成します。

コピーを回避するためにはbind(dist, ref(rng))と明示的に参照を渡してください。

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *