您要求提供 volatile 成员函数的实际示例。好吧,我想不出一个,因为我能想象的唯一情况是如此低级,以至于我一开始不会考虑使用成员函数,而只是一个简单的结构,其数据成员可通过 volatile 引用访问。
但是,为了回答这个问题,让我们在其中放入一个 const volatile 函数。假设您有一个地址为 0x378h 的端口,其中包含 2 个整数,每个 4 个字节。然后你可以写
struct ints {
int first;
int second;
int getfirst() const volatile {
return first;
}
int getsecond() const volatile {
return second;
}
// note that you could also overload on volatile-ness, just like
// with const-ness
};
// could also be mapped by the linker.
ints const volatile &p = *reinterpret_cast<ints*>(0x378L);
你在说
我没有改变它们,但是这个抽象语义之外的另一件事可能会改变它。所以总是从它的地址做一个真正的加载。
实际上,volatile表示对象的值可能不是最后存储到其中的值,但实际上是未知的,并且可能在外部(编译器无法观察到)条件之间发生了变化。因此,当您从 volatile 对象中读取数据时,编译器必须模拟确切的抽象语义,并且不执行任何优化:
a = 4;
a *= 2;
// can't be optimized to a = 8; if a is volatile because the abstract
// semantics described by the language contain two assignments and one load.
以下已经确定了做什么volatile
。一切都可以在1.9
标准中找到。它谈论的参数是实现定义的东西,比如某种类型的 sizeof。
本国际标准中的语义描述定义了一个参数化的非确定性抽象机。本国际标准对一致性实现的结构没有要求。特别是,它们不需要复制或模仿抽象机器的结构。相反,需要符合要求的实现来模拟(仅)抽象机的可观察行为,如下所述。[...]
执行格式良好的程序的一致实现应产生与具有相同程序和相同输入的抽象机的相应实例的可能执行序列之一相同的可观察行为。[...]
抽象机的可观察行为是它对易失性数据的读取和写入顺序以及对库 I/O 函数的调用。