How to call the seed_seq constructor of a random generator from a member initialization list?

时间:2018-10-24 11:24:08

标签: c++11 visual-c++ std

I have a class with a mersenne_twister_engine member that I want to initialize with a seed_seq constructed from a string. Initially I tried this:

class A
{
private:
    std::mt19937_64 rng;

public:
    A(std::string seed) : rng(std::seed_seq(seed.begin(), seed.end())) { }
};

But that doesn't compile, because:

(...) cannot convert argument 1 from 'std::seed_seq' to '_Seed_seq &'

I can get it to work like this:

class B
{
private:
    std::mt19937_64 rng;

public:
    B(std::string seed)
    {
        std::seed_seq seedSeq(seed.begin(), seed.end());
        rng = std::mt19937_64(seedSeq);
    }
};

But if I understand correctly, the member variable rng will now be constructed twice, so if possible, I'd like to avoid that. So, my main question is: Is it possible to make this work without initializing rng twice?

Before anyone suggests, I've also tried using a separate member function to construct the seed_seq object, but the only way I can get it to compile is by returning a const ref like this:

class C
{
private:
    std::mt19937_64 rng;

    const std::seed_seq& makeSeedSeq(std::string seed)
    {
        return std::seed_seq(seed.begin(), seed.end());
    }

public:
    C(std::string seed) : rng(makeSeedSeq(seed)) { }
};

Class C does compile, but when testing with different strings, the results are always the same and always as if the seed was an empty string. I guess this is because makeSeedSeq returns a reference to a local and the result is undefined behavior? This is an aside, but if someone could explain this and perhaps why seed_seq was implemented this way, I would very much appreciate it.

1 个答案:

答案 0 :(得分:2)

只需将std::seed_seq变量添加到std::mt19937_64之前的类中(变量初始化顺序很重要):

class A
{
private:
    std::seed_seq seed_seq;
    std::mt19937_64 rng;

public:
    A(std::string const& seed)
        : seed_seq(seed.begin(), seed.end())
        , rng(seed_seq)
    {}

    std::uint32_t uniform()
    {
        return std::uniform_int_distribution<std::uint32_t>()(rng);
    }
};

我也建议在构造函数中使用const&,以避免执行std::string复制构造函数。