实例化c ++ 11随机设施的正确方法是什么

Ger*_*ner 7 c++ random instantiation c++11

在查看了关于在C++中使用新的"随机"工具的各种示例之后,我对最佳实践感到有些困惑 - 特别是与各种实例的生命周期有关.

例如,在一些示例中,"random_device"的使用在诸如函数的局部范围中是静态的,或者是静态全局变量或者仅仅是本地的.

--- TU ---

static std::random_device global_source;


void foo()
{
   static std::random_device local_static_source;
   static std::mt19937 gen(local_static_source());
   std::uniform_int_distribution<> dist(0,10);
   ...
   dist(gen);
   ...
}

void boo()
{
   std::mt19937 gen(global_source());
   std::uniform_int_distribution<> dist(0,10);
   ...
   dist(gen);
   ...
}

void roo()
{
   std::random_device local_source;
   std::mt19937 gen(local_source());
   std::uniform_int_distribution<> dist(0,10);
   ...
   dist(gen);
   ...
}

int main()
{
   static std::mt19937 gen(global_source());
   std::uniform_int_distribution<> dist(0,10);
   ...
   dist(gen);
   ...
  return 0;
}

--- TU ---
Run Code Online (Sandbox Code Playgroud)

Q1:如果多个线程可以访问"foo"或"boo",那么生成器和源是否可以是静态的? - 有没有像shared_ptr那样的线程安全保证?

问题2:标准中是否有任何措辞可以讨论与实例化相关的假设和问题?

Cyg*_*gon 1

一些背景:允许随机数生成器的多个实例的原因主要是线程安全性(不会给随机数生成器实现带来线程同步的负担)和可重复性(允许使用相同的种子重复数字序列)。

  • 前者是不言自明的——在性能关键型代码中使用 RNG 是有效的。由于可以使用多个实例,因此不需要昂贵的互斥锁,并且可以在多个 CPU 内核上并行生成随机数。

  • 后者在随机生成数据集时通常很有用。作为一个常见的例子,视频游戏可以通过从相同的 RNG(甚至可能在不同的联网 PC 上)驱动与游戏世界创建相关的所有决策来重新创建相同的(随机)游戏世界。

因此,C++ RNG 的最佳范围取决于您正在编写的内容:

如果您正在编写一个可能在上述场景的上下文中使用的库,那么让调用者向各个方法或类提供 RNG 可能是一个好主意:

// Can be used on multiple CPU cores in parallel or with seed values
template <typename TRandomNumberEngine>
Point2 GetRandomPointInRectangle(
  const Rectangle2 &rect, TRandomNumberEngine &random
) {
  std::uniform_real_distribution<float> horizontal(rect.Min.X, rect.Max.X);
  float x = horizontal(random);

  std::uniform_real_distribution<float> vertical(rect.Min.Y, rect.Max.Y);
  float y = vertical(random);

  return Point2(x, y);
}
Run Code Online (Sandbox Code Playgroud)

如果您正在编写一个应用程序或一个库,该应用程序或库使用 RNG 作为支持角色(例如几何拟合算法),即。您只对不可重复的随机数感兴趣,随机数生成器的最佳范围将是最大可能的范围,不会在模块之间引入不必要的耦合。

这可能是任何需要随机数的类中的一个简单的私有对象变量,甚至是一个thread_local提供您选择的 RNG 的单例(如果它有很多短期消费者证明这种复杂性是合理的)。


发行版(如std::uniform_real_distribution)可以根据您的需要是短暂的。它们是普通函子,其中构造函数没有参数或仅存储执行函子时的参数。