我一直在阅读这个问题以及其他几篇答案,虽然我知道更改引用和更改当前实例的状态之间的区别,但我不确定为什么这意味着我不应该将其标记为只读。这是因为将某些东西标记为只读会告诉编译器实例的某些特殊信息,所以它能够将其视为线程安全,即使实际上可能并不是吗?
也许有些情况下我不希望实例能够被更改,但如果实例的状态发生变化我并不介意(例如单例)。如果我想要这样做,将实例标记为只读会有什么后果?
我一直在阅读这个问题以及其他几篇答案,虽然我知道更改引用和更改当前实例的状态之间的区别,但我不确定为什么这意味着我不应该将其标记为只读。这是因为将某些东西标记为只读会告诉编译器实例的某些特殊信息,所以它能够将其视为线程安全,即使实际上可能并不是吗?
也许有些情况下我不希望实例能够被更改,但如果实例的状态发生变化我并不介意(例如单例)。如果我想要这样做,将实例标记为只读会有什么后果?
没有(基于运行时/环境的)后果。编译器不会崩溃,运行时也不会出问题,一切通常都很好。
只有 FxCop(一些人使用的静态分析工具)才会对此发出警告。链接中解释了警告的原因(从语义上讲,可能不清楚对象实际上并非“只读”,而是变量无法“重新分配”)。
就我个人而言,我不同意这个规则,所以如果你正在运行 FxCop 并且它让你担心,我会禁用它。
http://ericlippert.com/2008/05/14/mutating-readonly-structs/
我向大多数人展示了这段代码,他们无法正确预测其输出。
可变的只读结构体存在一个问题,即人们认为它们正在改变它们,但实际上他们正在改变一个副本。
可变的只读引用类型则存在相反的问题。人们认为它们是深度不可变的,但实际上它们只是浅不可变的。
我认为重点在于这可能会误导人——一个不留神的读者可能会假设只读变量实际上是常量,但它并不是。
我认为应该把它视为建议而非规则——肯定有一些情况下可以使用,但需要小心使用。(特别是当可变状态暴露给外部世界时,我会感到紧张。)
这两种类型声明都是有效且有用的,尽管它们的含义不同:
如果你真的想要一个对可变对象的常量引用,被迫因任何原因而使用可变引用似乎是不合适的,更不用说是错误的了。在多线程编程中,常量引用可以避免您必须对拥有对象进行同步(您仍然需要通过引用对可变对象进行同步,但这是一种更细粒度的锁定)。
不谨慎的读者可能也是不谨慎的写作者 - 除了以下措施外,无法做太多事情:
const SourceRepository cvs = new ReadOnlyRepository(...);
C++有一种强制指向常量对象的常量指针的方式(引用在C++中略有不同):
Object const* const constantPointerToConstantObject = ...;
这是我在C#/Java中所缺少的几个C++功能之一。
D语言具有更好的关键字(immutable),它强制实现了可传递的不可变性。D的immutable允许编译器进行您担心的类型的优化,并保证安全性。D还支持const用于非传递性const,这意味着传递性和非传递性形式都是独立有用的。