D中的逻辑常量

Pet*_*der 13 d const const-correctness mutable

D有两种类型的const:不可变变量是声明为不可变的变量,并且总是不可变的,而const变量只是对象的只读版本.

逻辑const是将函数标记为const,但允许对一个或多个成员变量进行写访问.这种方法的典型用途是进行惰性评估,例如(在C++中)

struct Matrix
{
  double determinant() const
  {
    if ( m_dirty )
    {
      m_determinant = /* expensive calculation */;
      m_dirty = false;
    }
    return m_determinant;
  }

  void set(int i, int j, double x) { m_dirty = true; ...; }

  mutable bool m_dirty;
  mutable double m_determinant;
};
Run Code Online (Sandbox Code Playgroud)

在这里,determinant()const,但仍然可以修改m_dirty,m_determinant因为它们被标记为mutable.

d常量(FAQ)说,D2不支持,因为它提供了,这是造成障碍编写并发程序,并使得一定的优化更加困难弱势保证逻辑常量.

我完全理解这个问题,但是如果我们需要逻辑const呢?

考虑上面的情况与Matrix类,但没有缓存(和任何需要逻辑const).还想象一下,这个类在我的代码库中使用,并且主要通过const引用访问.

现在考虑分析已经揭示该determinant()函数是代码中的瓶颈,而且它通常被重复访问,其值很少改变,即如上所述的缓存将是完美的优化.

没有逻辑const我怎么能这样做呢?遍及我的代码库将const引用更改为非const引用不是一种选择(出于显而易见的原因).

我有什么选择(如果有的话)?

Jon*_*vis 11

我认为在这里发布D新闻组关于这个主题最新主题的基本结论是合适的,这样那些不跟踪该列表的人仍然可以得到适当的答案.

D的const不是逻辑const.它是传递性的,完全是常量的.该语言在技术上不支持逻辑const.该语言没有定义任何改变const对象的方法.

实际上,C++也没有逻辑const.使用mutable和转换const-ness允许你完全绕过const,这样,从技术上讲,const实际上并不保证任何东西,除了你没有在const变量上调用任何非const函数.const函数实际上是const并且不与变量混淆的事实完全按惯例保持在一起.现在,大多数程序员都不会左右摆放const-ness并使一切变得可变,所以在实践中它非常有用,但它不仅可以完全绕过,而且语言特别为你提供了定义的方法. .在C++中mutable,转换const是由语言定义和支持的.

D不这样做.D的const实际上是const.在一个变量上抛弃const然后改变它是未定义的.没有可变的.D的const有真正的保证(只要你不做任何未定义的东西,比如抛弃某些东西然后变异).这很重要,不仅因为D的编译器保证比C++的保证强得多,而且因为不可变变量不能以任何形式或形式改变.它们可能处于只读内存中,谁知道如果你试图抛弃不变性并改变这样一个变量会发生什么可怕的事情(段错误可能是最好的事情).并且因为const变量实际上可以引用不可变数据,所以抛出const来改变变量或允许以某种方式改变const变量将是坏事,至少可以说.所以,语言不允许这样做.

现在,正如BCS指出的那样,D是一种务实的语言.你可以抛弃const,此时你可以改变变量.因此,例如,您可以使用一个变量来缓存const函数的返回值(如果对象的状态发生变化,可能会使该缓存无效)并抛弃const来更改它.只要有问题的变量实际上不可变,它就会起作用.但是,这是未定义的行为.一旦你这样做,你就独自一人.你绕过了类型系统和编译器的保证.是负责确保您不在不可变对象上执行此操作或以其他方式搞砸编译器通常保证的内容的人.所以,如果你需要的话 要做到这一点,你可以,但是你正走进狂野的西部,并且由你来确保你不会改变你不应该做的事情.

假设只要变量实际上没有引用不可变数据,抛出const就会起作用,有可能创建一个Mutable模板来基本上得到mutable你在C++中提供的东西(所以,它会去掉const-ness为了你).he_the_great在他的回答中给出了这样一个模板的例子.但是使用这样的模板仍然是未定义的行为.在一个实际上不可变的对象上使用它会导致问题.,程序员,必须确保它被正确使用.

因此,D使得在技术上可以通过抛弃const来获得逻辑const,但是为了做到这一点,你必须绕过类型系统超出编译器保证的范围,并且你必须确保不要滥用它,不应该/不能突变发生变异的变量,或者你的代码就会有问题-段错误很可能是其中的最不.

编辑:我忘了提到一个破坏类型系统的建议解决方案.只要您愿意放弃纯度,就可以使用某种变量的全局变量(无论是在模块范围,类变量还是结构变量)来保存缓存值.const函数可以自由地使用和改变全局变量,因此它可以用来代替缺失mutable.然而,这确实意味着功能不能是纯粹的,这也可能是一个大问题.然而,这是一种使const函数仍然能够在不破坏类型系统的情况下改变它所需的数据的方法.