2010-09-30 133 views

回答

0

斯科特迈尔斯,Effective C++,第3项:

使用const尽可能

对这个话题的精彩讨论(举例)。很难写得比斯科特更好!

还要注意,物理常量也称为按位常量。

17

当对象中有可以被视为“内部”的字段时,即任何类的外部用户无法确定这些字段的值时,您需要mutable。尽管实例被认为是常量,即不改变,但该类可能需要写入这些字段。

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

这是不可能用C++干净地表达而不使相应的成员mutable,即使在标记为const的方法中也可以改变它们。正如在评论中指出的那样,你总是可以接触锤子并使用const_cast<>来移除const-,但这当然是作弊的。 :)

+3

另一个这样的例子是不同线程共享的对象中的互斥。读取操作不会修改对象,但必须在此过程中获取并释放互斥锁。在操作过程中,互斥成员对象会发生明显变化,即使操作的结果不会改变对象本身。即使内部元素发生变化,如果感知状态保持不变,对对象的操作也是常量。 – 2010-09-30 12:25:09

+0

可以请你给我一个小例子(代码),它显示了我可以做什么与mutable和不能与const,这也显示了逻辑和物理const'ness之间的区别我在谷歌找到一些解释但无法找到好例如,缓存有点难以理解 – rookie 2010-09-30 12:34:43

+0

_这是不可能用C++表达而不使相应的成员变为可变的。该陈述是不正确的,它可以通过转换对象或成员来消除常量,从而完成(并在过去)。关键字'mutable'出现后,当逻辑常量的概念被实现时,因为程序员为了获得这种效果而去除了对象的常量,使得它更易于维护和强制执行。参见[这里](http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter08_025.html)。 – Adrian 2014-06-04 20:08:50

31

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

“逻辑”常量来自声明引用或指针const,并由编译器强制执行。对象本身可能是“物理”常量,也可能不是,但引用不能用于在没有强制转换的情况下对其进行修改。如果对象不是“物理”常量,则C++允许您修改它,使用const_cast来规避保护。

A mutable即使类对象本身(或用于访问它的引用或指针)为const,也可以修改类成员。这样做的好用例子是在读取操作期间必须锁定的互斥锁,以及用于存储昂贵读取操作结果的缓存。在这两种情况下,操作本身应该是const函数(因为它不影响对象的可见状态),但它需要修改互斥锁或缓存,因此这些操作必须是mutable。它也可能被滥用,使得物体在逻辑上不可见时发生明显的变化,因此小心使用它;如果它们不构成外部可见状态的一部分,则仅声明成员mutable

+1

+1,非常好的解释。 – Dan 2010-10-01 13:44:10

+1

这样读得非常好:-),但是非常错误:-(。“”物理“常量来自声明一个对象const” - “const”不能保证你的“物理常量”:成员可能仍然是“可变的”并在运行时更改,因为这是允许的,编译器/链接器等不会将这些对象默认放置在只读存储器中,即使它们是“静态常量”,如果它们被迫通过某些非标准的编译器/链接器/加载器标志,然后程序员必须手动避免'mutable'成员。你在对象和指针/引用之间绘制的区别实际上是不相关的。 – 2011-07-28 01:49:16

+0

@TonyDelroy-我带着Mike的回应,只有记忆“作为一种修辞(和修辞有效)的陈述来表达关于物理和逻辑”常量“之间差异的观点,而不是表明编译者会真正做到这一点;他也没有声明编译器会*做这也是我不同意他的disti指针和引用之间的连接是无关紧要的。答案在概念上是坚实和正确的。在我看来,TonyDelroy在说他的答案“非常错误”时并不正确。 – 2012-05-29 05:02:54