我问自己这个问题为什么
#include <random>
struct A{
std::random_device rd; // or any other generator std::mersenne_twister...
void doStuff() const {
auto v = rd();
}
};
const A a;
a.doStuff();
不起作用,因为random_device::operator()
不是const
。
我想也许随机设备仍然可以在常量时使用,但它不能再次播种,但事实并非如此(内部状态显然在std::random_device
中不可变)...
我想让A类正确定义(doStuff()
是一个const方法)现在我突然需要使用mutable std::random_device rd;
并不是那么难看?
这种设计有什么理由吗?
答案 0 :(得分:9)
std::randome_device::operator()()
不是const
,因为它可能会修改对象的内部状态。 std::random_device
可以是伪随机数生成器,它使用内部状态生成数字。每次生成一个数字时,都必须修改内部状态,否则每次都会得到相同的数字。
答案 1 :(得分:7)
const
可能意味着许多事情。它可能意味着以下任何或所有:
给定相同的对象状态和参数,将会发生相同的结果。
该功能不会改变其操作对象的内部状态。
该函数访问thread-safe way中对象的状态。
这些都不适用于random_device::operator()
。你会得到不同的结果; 这是功能的重点。对象内部的状态将受到请求(以某种方式)的影响。并且该功能最确定不线程安全;在不同线程的同一个对象上调用它会导致所有不良的庄严。
任何RNG都是如此。从RNG获取随机数本质上非常数过程。这就是为什么C ++ 11 RNG的设计要求operator()
不被声明为const
。
至于你的目标:
我想让A级正确定义(
doStuff()
是一种const方法)现在我突然需要使用mutable std::random_device rd;
那不丑吗?
这取决于const
的含义。显然#2已经出局,因为你将改变mutable
状态。但是,对于&#34;相同结果&#34;的特定定义,您仍然可以提供#1。也就是说,&#34;东西&#34; doStuff
确实在逻辑上是一致的。显然不是二进制相同,而是在函数行为的范围内。这足以成为const
。
您甚至可以通过在互斥锁中包含对mutable
RNG对象的访问权来提供#3。
这样的案例正是mutable
被发明的原因。它不丑陋;您只需将该功能用于其设计目的。允许您以逻辑const
的方式访问某些非const
个对象到调用方。