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
,因为它从未使用过。
一个对象可以同时标记为const
和volatile
!你不能改变物体,但它可以在你背后改变。
@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,mutable
reference_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的主要内容,如果未能解决你的问题,请参考以下文章