逻辑和物理常数之间的差异

roo*_*kie 24 c++

这两个术语有什么区别,为什么我需要mutable

Mik*_*our 38

"物理"常量来自声明一个对象const,并且原则上可以通过将对象放在只读内存中来强制执行,因此它不能更改.试图改变它会导致不确定的行为; 它可能会改变,也可能不会,或者它可能会触发保护错误,或者它可能会熔化内存芯片.

"逻辑"constness来自声明引用或指针const,并由编译器强制执行.对象本身可能是也可能不是"物理"const,但是如果没有强制转换,则不能使用引用来修改它.如果对象不是"物理上"const,那么C++允许您修改它,const_cast以避免保护.

mutable类构件可以修改即使类对象本身(或用于访问它的引用或指针)是const.这方面的良好用途的示例是在读取操作期间必须被锁定的互斥锁,以及用于存储昂贵的读取操作的结果的高速缓存.在这两种情况下,操作本身应该是一个const函数(因为它不会影响对象的可见状态),但它需要修改互斥锁或缓存,所以这些都需要mutable.它也可能被滥用,使物体在逻辑上不应该明显改变,所以要小心使用它; mutable如果成员不构成外部可见状态的一部分,则仅声明成员.

  • 读起来很好:-),但是非常错误:-(。““物理”常量来自声明一个对象 const” - `const` 不会保证你的“物理常量”:成员可能仍然是“可变的”并且在运行时更改。因为这是允许的,所以编译器/链接器等默认情况下不会将此类对象放置在只读内存中,即使它们是“static const”。如果它们通过某些非-标准编译器/链接器/加载器标志,那么程序员必须手动避免“可变”成员。对象和指针/引用之间的区别实际上是无关紧要的。 (2认同)
  • @TonyDelroy - 我将迈克的回应涉及“将对象放入只读内存”作为修辞(并且修辞上有效)的陈述来说明物理和逻辑“常量”之间的差异,而不是作为编译器的陈述实际上会这样做;他也没有声明编译器*会*这样做。另外,我不同意他对指针和引用之间的区别是无关紧要的。答案在概念上是可靠且正确的。在我看来,托尼·德尔罗伊所说的答案“非常错误”是不正确的。 (2认同)

unw*_*ind 17

mutable当对象中的字段可以被视为"内部"时,您需要,即该类的任何外部用户都无法确定这些字段的值.即使实例被认为是常量,即不改变,类也可能需要写入这些字段.

考虑硬盘; 它的缓存就是这种状态的一个例子.从实际磁盘读取数据时写入缓存.

如果没有相应的成员mutable,就不可能在C++中干净利落地表达,即使在标记的方法中也允许更改它们const.正如评论中指出的那样,你总能找到锤子并使用a const_cast<>去除const-ness,但这当然是作弊.:)

  • 另一个这样的示例是由不同线程共享的对象中的互斥锁.读取操作不会修改对象,但必须在此过程中获取并释放互斥锁.即使操作结果不改变对象本身,互斥成员对象在操作期间也会明显改变.如果感知状态保持不变,则操作是对象的const,即使内部元素发生变化. (3认同)

Aru*_*run 6

Scott Meyers,《有效的 C++》,第 3 条:

const尽可能使用

关于这个主题有一个精彩的讨论(带有示例)。很难写得比斯科特更好!

另请注意,物理常量也称为按位常量。