随机分布应该通过引用传递还是作为 C++ 中的对象成员

Gra*_*per 3 c++ random math generator

假设我们只实例化少于 20 个 Blob 类对象,并且考虑到效率(执行时间)和内存管理问题,是否有最佳选择:

  • 将随机生成器和生成的分布设置为私有类成员,例如:

    class Blob {
    private:
    std::mt19937 engine;
    std::uniform_real_distribution<double> R_distribution;
    std::binomial_distribution<int> B_distribution;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    并直接在 Blob 方法中使用它们。因此,当我们调用发行版时,我们也会更改作为成员的引擎的状态。

  • 或者将随机生成器设置为私有类成员并通过引用方法传递分布?例如:

    class Blob {
    private:
    std::mt19937 engine; //engine
    }
    
    void Blob::run() {
    int blabla = 10;
    std::uniform_real_distribution<double> R_distribution(0, 10);
    do_something(blabla, R_distribution);
    ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

虽然通过引用传递通常会降低开销,但在这种情况下特别重要吗?当多次调用分布(10^9 或更多)时,总体问题如何扩展?

use*_*840 5

发行版很便宜,并且可以随意创建/丢弃。发动机则不然。理想情况下,您应该只初始化 PRNG一次,并确保thread_local您的程序是多线程的。PRNG 之类的std::mt19937体积庞大并且具有很大的内部状态。考虑做这样的事情:

inline auto global_rng() -> std::mt19937& {
    thread_local std::mt19937 e{ get_seed() };
    return e;
}

void foo() {
    thread_local std::uniform_real_distribution<double> d; 
    // ...
}
Run Code Online (Sandbox Code Playgroud)

  • uniform_real_distribution 可能很便宜,但据我所知,标准中没有任何内容表明*所有*发行版“都可以随意创建/丢弃”......这应该根据每个发行版类来决定(可能在一些分析之后) (2认同)