11

我正在阅读有关 volatile 成员函数的内容,并确认成员函数可以同时是const 和 volatile。我没有得到这种东西的真正用途。任何人都可以分享他们将成员函数作为 const 和 volatile 一起实际使用的经验。

我写了小班来测试同样的:

class Temp
{
public:

    Temp(int x) : X(x)
    {
    }

    int getX() const volatile
    {
        return X;
    }

    int getBiggerX()
    {
        return X + 10;
    }
private:
    int X;
};

void test( const volatile Temp& aTemp)
{
    int x = aTemp.getX();
}

int main(int argc, char* argv[])
{
    const volatile Temp aTemp(10);
    test(aTemp);

    return 0;
}
4

6 回答 6

18

cv资格蒸馏意味着:

我不会改变这个值,但是有一些东西可以。

您向自己承诺不会更改值(const限定),并要求编译器保持对这个对象的黏糊糊的手并关闭所有优化(volatile限定)。不幸的是,在公平对待方面,编译器供应商几乎没有标准volatile。毕竟volatile是对编译器的提示

一个实际用例是系统时钟。假设 0xDEADBEEF 是您要编写的硬件时钟寄存器的系统特定地址:

int const volatile *c = reinterpret_cast<int *>(0xDEADBEEF);

您无法修改该寄存器值,但每次读取它时,它都可能具有不同的值。

此外,可以使用它来模拟UART

于 2009-03-17T16:40:32.903 回答
13

您要求提供 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 函数的调用。

于 2009-03-17T17:02:47.000 回答
1

我从来不需要任何既是 const 又是 volatile 的东西,但这是我的猜测:

Const:您,您的代码,不允许更改该值。

Volatile:该值可能会随着时间而改变,而您的程序没有做任何事情。

因此,由另一个进程或某些硬件公开的一些只读数据将是 const 和 volatile。它甚至可以被内存映射到您的进程中,并且页面标记为只读,因此如果您尝试写入它而不是 const,您会遇到访问冲突。

于 2009-03-17T16:40:16.900 回答
1

我认为我们有“const volatile”函数的原因与我们有“受保护”继承的原因是一样的:语法允许它,所以我们最好想出一个含义。

于 2009-03-17T18:26:06.397 回答
1

我能想到的一种情况可能需要在成员函数上同时使用 const 和 volatile ,这是在嵌入式系统情况下,您的函数在逻辑上是 const 但实际上必须修改共享内存位置中的数据缓存(例如,构建一个按需位图并缓存位图,以防很快再次需要相同的位图)。它当然不会经常出现。

于 2009-03-18T03:10:00.437 回答
1

标记为 const volatile 的对象将不允许被声明它的代码更改。由于 const 限定符,将引发错误。限定符的 volatile 部分意味着编译器无法针对对象优化代码。

在嵌入式系统中,这通常用于访问可由硬件读取和更新的硬件寄存器,因此能够通过代码写入寄存器是没有意义的。一个示例可能是串行端口的状态寄存器。各种位将指示状态,例如字符是否正在等待读取。根据串行端口硬件中发生的其他情况,对该状态寄存器的每次读取都可能导致不同的值。写入状态寄存器没有意义,但您需要确保每次读取寄存器都会导致实际读取硬件。

下面是一个插图:

//We assume that the below declared pointers
//point to the correct
//hardware addresses
unsigned int const volatile *status_reg;
unsigned char const volatile *recv_reg;

#define CHAR_READ 0x01

int get_next_char()
{
    while((*status_reg & CHAR_READ) == 0);
    return *recv_reg;
}

希望这可以帮助。

问候 Sandipan Karmakar。

于 2013-03-17T16:12:19.987 回答