在C++结构体/类中,非静态成员变量是否需要标记为volatile才能在成员函数中被视为volatile?

46
class MyClass
{
    int x, y;
    void foo() volatile {
        // do stuff with x
        // do stuff with y
    }   
};

我需要将xy声明为volatile,还是所有成员变量都会自动被视为volatile

我想确保编译器不会重新排列“与x相关的内容”和“与y相关的内容”。

编辑: 如果我将普通类型转换为volatile类型会发生什么?这会指示编译器不要重新排列对该位置的访问吗?我想在特殊情况下将普通变量传递给参数为volatile的函数。我必须确保编译器不会将该调用与先前或后续的读写重新排序。


什么是C++中volatile成员函数的目的? - Peter Cordes
4个回答

43
将成员函数标记为volatile就像将其标记为const一样;这意味着接收器对象被视为声明为volatile T*。因此,在成员函数中对xy的任何引用都将被视为volatile读取。此外,volatile对象只能调用volatile成员函数。
话虽如此,如果您确实希望所有对xy的访问都被视为volatile,则可能仍然希望将它们标记为volatile

10

您不需要明确声明成员变量。

根据标准文档9.3.2.3

同样,在访问对象及其非静态数据成员时,volatile语义(7.1.6.1)适用于volatile成员函数


8
以下代码:
#include <iostream>

class Bar
{
    public:

        void test();
};

class Foo
{
    public:

        void test() volatile { x.test(); }

    private:

        Bar x;
};

int main()
{
    Foo foo;

    foo.test();

    return 0;
}

使用gcc编译时会引发错误:

main.cpp: In member function 'void Foo::test() volatile':
main.cpp:14:33: error: no matching function for call to 'Bar::test() volatile'
main.cpp:7:8: note: candidate is: void Bar::test() <near match>

由于一个volatile实例无法调用一个non-volatile方法,我们可以假设,在该方法中,即使MyClass的实例未声明为volatilexy也将是volatile的。
注意:如果需要,您可以使用const_cast<>来移除volatile限定符;但是要小心,因为就像const一样,这样做可能会在某些情况下导致未定义的行为。

如果我理解有误,请纠正我,但是volatile函数的语义不是与const函数相同吗?也就是说,您可以在非volatile对象上调用volatile函数,但不能从volatile对象调用非volatile函数。 - templatetypedef
@ereOn- 在g++中进行的快速测试表明,您确实可以从非volatile对象调用volatile成员函数。 volatile std :: string无用的原因是,如果字符串本身是volatile,则只能调用volatile成员函数,而其中没有任何成员函数。 标准的$4.4.1澄清了您可以将T *隐式转换为volatile T *,而$9.3.1.3表示volatile限定符会影响this指针,这表明如果您有一个类型为T的对象,则类型为T *的this指针可以转换为volatile T *以进行调用。 - templatetypedef
@templatetypedef:我反转了逻辑(这里才早上7点,我还需要一些睡眠;))。谢谢,现在已经修复了。您可以从volatilenon-volatile实例中调用volatile方法。但是,如果您的实例是volatile,则无法调用non-volatile方法。 - ereOn
@ereOn:所以,就像templatetypedef说的那样,它与“const”完全一样。相关部分当然不是g++,而是标准:4.4.1条款似乎表明,将“this”从“T”隐式转换为“volatile T”是完全合法的。此外,请注意,9.3.2.4明确指出,如果您调用对象表达式与成员函数“一样或比其少cv-qualified”,则可以对带有cv限定符的函数进行调用。在这个领域,没有区别constvolatile - Christopher Creutzig
关于类型转换:如果原始对象确实被定义为volatile,并且您将此对象或其成员之一作为左值(实质上是在赋值的左侧)访问为非volatile的某个东西,标准的7.1.5.1.7条款说明程序行为是未定义的。即使它在当前编译器版本和测试数据上工作,也不要这样做。就我所知,对于只读访问(就像const一样),类型转换应该是可以的。 - Christopher Creutzig
你误解了我的意思,我的意思是:是否可能将一个实际上被声明为非易失性的对象转换为易失类型。反过来做对我来说很清楚。 - 0xbadf00d

3

因此,以原始示例为例:

class MyClass
{
    int x, y;
    void foo() volatile {
        // do stuff with x
        // do stuff with y
        // with no "non-volatile" optimization of the stuff done with x, y (or anything else)
    }   
    void foo() {
        // do stuff with x
        // do stuff with y
        // the stuff done with x, y (and anything else) may be optimized
    } 
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接