【问题标题】:when should a member function be both const and volatile together?成员函数什么时候应该同时是 const 和 volatile ?
【发布时间】:2009-03-17 16:36:33
【问题描述】:

我正在阅读有关 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;
}

【问题讨论】:

    标签: c++ constants volatile


    【解决方案1】:

    cv资格提炼的意思是:

    我不会更改值,但有一些东西可以。

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

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

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

    你不能修改那个寄存器的值,但是每次你读取它时,它很可能有不同的值。

    另外,可以用它来建模UARTs

    【讨论】:

    • 添加到“……可以的东西。”,我总是想从内存而不是 CPU 寄存器或缓存中读取值。
    • 我已经在编辑我的帖子了,因为它有点太短了。
    • 作为一个嵌入式的人,我一直使用指向 const volatile 的指针(就像你的例子一样。)但我认为 OP 想要一个例子来说明它何时适用于成员函数,而不是指针.
    • 如果可以将其用于变量,则可以将其扩展为函数。我认为这是自然的。
    • @dirkgently,编译器会假定 const 限定函数在每次调用时返回相同的结果吗?以要求不稳定的资格?
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      Const:你,你的代码,不允许改变值。

      易失性:该值可能会随着时间而改变,而您的程序不会做任何事情。

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 受保护的继承是一个错误。 “const volatile”有一个非常好的含义——代码不会改变值,但其他东西可能会。
        • 我的意思是(显然我会从上下文中想到)“const colatile”成员函数。
        • 啊,我在看代码。不过,“const volatile”成员函数有什么问题?我不确定 volatile 成员函数有很多用途,但如果是这样,它们没有理由也不应该是 const。
        • 受保护的继承是/不是一个错误。将它用于错误的事情只是一个错误。
        • 他询问了成员函数。我不确定为什么这么多人实际上想出了易失性变量作为答案和 cmets :) 到目前为止,尼尔和我的似乎是唯一真正回答他的问题的答案。
        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          标记为 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。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-06-03
            • 1970-01-01
            • 2020-07-16
            • 1970-01-01
            • 2019-07-08
            • 1970-01-01
            相关资源
            最近更新 更多