C++ 中的 volatile 与 mutable

Posted

技术标签:

【中文标题】C++ 中的 volatile 与 mutable【英文标题】:volatile vs. mutable in C++ 【发布时间】:2010-03-15 02:11:40 【问题描述】:

我对 volatile 和 mutable 之间的区别有疑问。我注意到这两者都意味着它可以改变。还有什么?它们是一样的吗?有什么不同?它们适用于什么地方?为什么提出这两个想法?如何以不同的方式使用它们?

非常感谢。

【问题讨论】:

【参考方案1】:

即使在通过const 指针或引用访问的对象或const 对象中也可以更改mutable 字段,因此编译器知道不将其存储在R/O 内存中。 volatile 位置可以通过编译器不知道的代码(例如某些内核级驱动程序)进行更改,因此编译器知道不进行优化,例如在该值“不可能改变”的无效假设下对该值的寄存器分配,因为它最后一次加载到该寄存器中。向编译器提供非常不同类型的信息以阻止非常不同类型的无效优化。

【讨论】:

volatile 对象也可以被完全不涉及 CPU 的进程更改。例如,通信外设中的字节接收寄存器可以在接收到字节时增加自身(这甚至可以触发中断)。另一个例子是外设中的挂起中断标志寄存器。 另外,volatile 不仅意味着对象可以在编译器不知道的情况下发生变化 - 它还意味着编译器无法消除对对象的写入,即使这些写入看起来没用。例如:x = 1; x = 0; 如果x 是易失性的,编译器必须发出两个写操作(这在硬件级别可能很重要)。但是,对于非易失性对象,编译器可以选择不编写 1,因为它从未使用过。 一个对象可以同时标记为constvolatile!你不能改变物体,但它可以在你背后改变。 @Destructor:通常情况是写入硬件设备寄存器。 @Destructor 假设您正在控制 LED 的状态。写入 0 将其关闭,写入 1 将其打开。如果我需要闪烁 LED 以传达某些错误状态,但编译器决定优化除最后一个之外的所有写入,因为没有使用任何值,那么 LED 永远不会闪烁并且我想要的行为没有实现.【参考方案2】:

mutable: mutable 关键字覆盖任何封闭的 const 语句。可以修改 const 对象的可变成员。

volatile: volatile 关键字是一个依赖于实现的修饰符,在声明变量时使用,它会阻止编译器优化这些变量。 Volatile 应与其值可能以意外方式(即通过中断)发生变化的变量一起使用,这可能与编译器可能执行的优化冲突。

Source

【讨论】:

你说Volatile should be used with variables whose value can change in unexpected ways我们应该更喜欢随机使用它吗? @AsifMushtaq 不是值。方法。可变影响您编写的代码的权限。因此,您可以通过 const ptr 或 const 引用访问该变量。如果不是您的代码更改它怎么办?编译器无法检查 ptr 或引用类型的东西?那是易变的。并且 volatile 还会强制缓存写回主存。因此,这在多线程代码中被大量使用。 :)【参考方案3】:

它们绝对不是一回事。 Mutable 与 const 交互。如果你有一个 const 指针,你通常不能改变成员。 Mutable 为该规则提供了一个例外。

另一方面,Volatile 与程序所做的更改完全无关。这意味着内存可能由于编译器无法控制的原因而发生变化,因此编译器必须每次都读取或写入内存地址,并且无法将内容缓存在寄存器中。

【讨论】:

“另一方面,Volatile 与程序所做的更改完全无关......” - 嗯,让一个成员 volatile 看看在编译期间有什么中断.尝试在事后添加 volatile 很像尝试在事后添加 const ......很痛苦。 @jww:这与程序的写入完全无关。您可以获取T 类型对象的地址,并将其存储到const T* 中并从中读取。如果您将该对象设为volatile,则将其地址存储到const T* 将失败,即使您从未尝试写入。 volatile 和程序代码的更改/修改/内存写入是完全正交的。【参考方案4】:

一种粗略但有效的思考差异的方法是:

编译器知道可变对象何时发生变化。 编译器无法知道 volatile 对象何时更改。

【讨论】:

同理:volatile bytes_received,mutablereference_count。【参考方案5】:

标记为mutable 的变量允许在声明为const 的方法中对其进行修改。

标记为volatile 的变量告诉编译器它必须在每次代码告诉它时读取/写入变量(即它无法优化对变量的访问)。

【讨论】:

【参考方案6】:

我想补充一点,在处理多线程应用程序时,volatile 也非常有用,即你有你的主线程(main() 所在的地方)并且你生成了一个工作线程,它会在变量“app_running”时保持旋转是真的。 main() 控制“app_running”是真还是假,所以如果没有在“app_running”的声明中添加volatile属性,如果编译器在辅助线程运行的代码中优化了对“app_running”的访问,main( ) 可能会将“app_running”更改为 false,但辅助线程将继续运行,因为该值已被缓存。我已经在 Linux 和 VisualC++ 上使用 gcc 看到了相同的行为。 “app_running”声明中的“volatile”属性解决了这个问题。因此,这是在更改此类变量的值时不涉及硬件中断或内核的情况。

【讨论】:

不!这是一个常见的误解。 C++11 和 C11 为此引入了原子***.com/questions/8819095/…

以上是关于C++ 中的 volatile 与 mutable的主要内容,如果未能解决你的问题,请参考以下文章

深入理解C++中的mutable关键字

C++ 各类型转换及关键字

mutable关键字

C++中的volatile是啥意思?

限定符

C++ mutable 数据成员