C++ 恒定正确性和<;随机>;

C++ 恒定正确性和<;随机>;,c++,c++11,random,constants,mutable,C++,C++11,Random,Constants,Mutable,处理(否则)包含C++11随机类的随机生成器调用的常量函数的正确方法是什么?您是希望放弃函数的常量标志,还是最好将生成器和分发声明为类的可变元素? 最简单的示例(非编译)可能是: #include <random> class foo { std::mt19937 MyGenerator; std::normal_distribution<precision_type> gauss; double get_rnd() const {return gauss

处理(否则)包含C++11随机类的随机生成器调用的常量函数的正确方法是什么?您是希望放弃函数的常量标志,还是最好将生成器和分发声明为类的可变元素? 最简单的示例(非编译)可能是:

#include <random>

class foo 
{
  std::mt19937 MyGenerator;
  std::normal_distribution<precision_type> gauss;
  double get_rnd() const {return gauss(MyGenerator);}
};
#包括
福班
{
标准:mt19937 MyGenerator;
正态分布高斯;
双get_rnd()常量{返回高斯(MyGenerator);}
};
该关键字是为此类案例设计的。使用此修饰符标记random generator实例字段时,即使在封闭类的
const
方法中,也允许更改其状态


一般来说,这似乎是一个灰色区域,取决于您的类所代表的概念类型。如果生成器的状态在概念上与此类的状态无关,则此解决方案是可以的。否则,您应该重新考虑设计-如果生成器的状态是相关的,那么使用它的方法不应该是
const

,这实际上取决于您为
const
成员访问赋予了什么语义

对于标准类,从多个线程并发调用
const
成员是线程安全的。如果让成员
const
变异RNG,则会破坏这一点,除非RNG是完全线程安全的(对于非
const
使用)

您不必以同样的方式设计类,但是其他开发人员可能会发现发现发现不能同时安全地“读取”(invoke
const
member functions)的类很混乱


一种选择是提供两种变体——使用内部存储的RNG的非常量版本和通过非常量引用接受RNG的
const
版本。(第一个可以调用第二个,无需
const\u cast
required)。这实现了“只为您需要的东西付费”准则w.r.t线程安全,因为如果每个线程都提供一个线程本地RNG实例,那么多个线程可以安全地使用该对象。它还允许使用模拟RNG实现进行测试,这可能更有价值。

我认为这取决于您的用例。如果您想要一些完全确定的行为,您必须删除const标志以确保您的类的状态不能更改,那么它就不会被更改。如果编写安全相关代码或必须进行可复制测试的代码,这可能很重要。

这取决于您想要实现的目标,典型策略包括:

  • 暴露易变性。只是不要将该方法标记为
    const

  • 外部化以暴露易变性。将可变元素(这里是生成器和分发)作为方法参数传递,在内部公开可变性的使用,调用方负责任何线程安全含义

  • 实现“逻辑”恒定。如果随机性的使用不被认为破坏了类的逻辑常量,那么您可以简单地将生成器和分布声明为
    可变的
    ;注意线程安全问题(如有必要,即在多线程应用程序中,使用
    mutable
    mutex)


  • 您选择哪种选择取决于您要实现的语义。

    您能举个小例子吗?如果
    random
    实例没有试图变异类的任何成员,并且本身不是成员,那么函数仍然可以保持
    const
    @Cyber:根据这个问题,似乎很清楚
    random
    实例是成员(问题称为“元素”)。一个考虑因素可能是线程安全。Const方法通常被视为线程安全的。因此,如果调用受内部互斥体的保护,对我来说,将其变为可变成员似乎是可以的,否则,如果涉及多线程的可能性很小,则不会。如果每次都返回不同的值,则希望将其声明为常量似乎有点奇怪。这会让用户感到困惑。用户希望,如果调用常量对象的方法,它将是幂等的。@Cyber:问题中添加了一个最小的示例。不过,我认为在这种情况下这不是一个好主意
    mutable
    用于帮助实现逻辑上的-
    const
    方法。调用RNG在逻辑上不是-
    const
    @OliverCharlesworth这是一个很好的观点,但是我认为这是一个灰色区域,取决于类所表示的概念(更新了答案)。我假设相同的参数适用于返回当前时间的方法,只要您可以自己为所提供的RNG设定种子(例如,类构造函数允许您提供),那么即使没有模拟,测试也不太成问题,因为您已经确定了。当你希望第六调用返回5中的第一个未返回的特定值时,模拟变得更有价值……在C++中,我们称之为成员函数;BenVoigt:标准确实如此,但口语化的用法似乎更倾向于将“方法”作为一个缩写:)方法这个术语在计算机科学中有其含义。在C++中不加区分地应用它的用户要么来自java,要么有方法,要么没有充分理解C++成员函数不是默认的代码>虚拟<代码>,或者货品编译器只重复他们听到的内容。