我的代码中有以下实现:
// first solution
//random.h
class Random{
public:
std::mt19937* gen;
std::uniform_real_distribution<double>* dis;
}
//random.cpp
Random::Random()
{
std::mt19937_64::result_type seed = chrono::high_resolution_clock::now().time_since_epoch().count();
gen = new std::mt19937(seed);
dis = new std::uniform_real_distribution<double>(0.0,1.0);
}
double Random::next()
{
double rand = 0;
rand_int = (*dis)(*gen);
return rand;
}
另一方面,公司中的其他人做了不同的实现,他使用c ++ 11中的bind
功能,如下所示:
// second solution
//random.h
class Random{
public:
std::function<double()> real_rand;
}
//random.cpp
Random::Random()
{
std::mt19937_64::result_type seed = chrono::high_resolution_clock::now().time_since_epoch().count();
real_rand = std::bind(std::uniform_real_distribution<double>(0.0,1.0), mt19937_64(seed))
}
double Random::next()
{
double rand = 0;
rand = real_rand();
return rand;
}
考虑到你应该只有一个PRNG对象,你应该播种一次,然后你每次需要一个新的随机数时调用该对象,因为种子用于创建一系列PRNG中的随机数。我可以清楚地看到第一种解决方案就是这种情况。
问题是,bind()
如何在幕后工作?它是否在每次通话时都创建了一个新对象?是真的在调用(constructor)
还是function()
?它怎么能告诉哪个人打电话?这些解决方案之间有什么不同吗?
答案 0 :(得分:4)
std::bind
生成一个函数对象,它封装了提供给它的参数。实际上,您的同事的代码会生成以下对象:
struct random_call
{
random_call(unsigned seed)
: _mt19937_64(seed)
, _uniform_real(0.0, 1.0)
{}
double operator() {
return _uniform_real(_mt19937_64);
}
std::mt19937_64 _mt19937_64;
std::uniform_real_distribution<double> _uniform_real;
};
所以它看起来很好(实际上非常聪明)给我!
有一点需要注意的是,您可能不希望制作活页夹对象的任何副本 - 即使它是可复制的,复制它然后在原始文件上调用operator()
,副本将产生相同的数字。