什么时候成员函数应该是const和volatile一起?

时间:2009-03-17 16:36:33

标签: c++ const 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;
}

6 个答案:

答案 0 :(得分:17)

提取 cv 资格意味着:

  

我不会改变价值,但有些东西可以改变。

您正在向自己承诺,您不会更改值(const资格)并要求编译器保持其对象的粘性,并关闭所有优化(volatile资格)。不幸的是,在公平地处理volatile时,编译器供应商几乎没有标准。毕竟,volatile是编译器的提示

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

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

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

此外,可以使用它来建模UARTs

答案 1 :(得分:13)

您要求提供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 表示对象的值可能不是最后存储在其中的值,但实际上是未知的,并且可能在外部(编译器无法观察)条件之间进行了更改。因此,当您从易失性对象中读取时,编译器必须模拟确切的抽象语义,并且不执行任何优化:

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函数的调用。

答案 2 :(得分:1)

我从来不需要任何常量和易变的东西,但这是我的猜测:

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

Volatile :如果没有您的程序执行任何操作,该值可能会随时间而变化。

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

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

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

以下是插图:

//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。