thread-local static uniform_int_distribution, will it be recreated for different sets of min, max?

∥☆過路亽.° 提交于 2019-12-23 04:02:27

问题


In this answer on stackoverflow (answer #2) @remyabel recommends this template:

#include <random>

std::mt19937& prng_engine()
{
  thread_local static std::random_device rd{};
  thread_local static std::mt19937 engine{rd()};

  // Or you can replace the two previous lines with:
  //thread_local static std::mt19937
  //  prng{std::random_device{}()};

  return engine;
}

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
    thread_local static std::uniform_int_distribution<T> dist{Min, Max};
    return dist(prng_engine());
}

Will dist be created only once for give set of {T, Min, Max} in thread?

If I call it with (1, 10) and then with (11, 20) will it be recreated or not?


回答1:


because it is static, dist is created only once - the first time code flows over it.

The first time code flows over it, the values of Min and Max will be 1 and 10.

On the second call, dist is not re-created so the new values of Min and Max are ignored and you get a random number between 1 and 10.

edit:

here's an implementation of getRandomNumberBetween that does what you want:

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
    using range_t = std::pair<T, T>;
    using map_t = std::map<range_t, std::uniform_int_distribution<T>>;
    static thread_local map_t range_map;

    auto i = range_map.find(range_t(Min, Max));
    if (i == std::end(range_map))
    {
        i = range_map.emplace(std::make_pair(Min, Max), std::uniform_int_distribution<T> { Min, Max}).first;
    }
    return i->second(prng_engine());
}



回答2:


It will be created only once for every T (each instantiation of function template has its own copy of local static variables). You can check with:

std::cout << getRandomNumberBetween(0, 1) << '\n'
          << getRandomNumberBetween(10, 20) << '\n'
          << "------------------------\n"
          << getRandomNumberBetween('a', 'b') << '\n'
          << getRandomNumberBetween('c', 'z') << '\n';

Since distribution objects are lightweight, you can simply construct a new distribution when you need a random number (e.g. Vary range of uniform_int_distribution):

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
  std::uniform_int_distribution<T> dist{Min, Max};
  return dist(prng_engine());
}

However you can also consider this implementation:

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
  using distribution_type = std::uniform_int_distribution<T>;
  using param_type = typename distribution_type::param_type;

  thread_local std::uniform_int_distribution<T> dist;
  return dist(prng_engine(), param_type(Min, Max));    
}


来源:https://stackoverflow.com/questions/30096963/thread-local-static-uniform-int-distribution-will-it-be-recreated-for-different

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!