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

Do I need to declare x and y as volatile or will be all member variables treated as volatile automatically?

I want to make sure that "stuff with x" is not reordered with "stuff with y" by the compiler.

EDIT: What happens if I'm casting a normal type to a volatile type? Would this instruct the compiler to not reorder access to that location? I want to pass a normal variable in a special situation to a function which parameter is volatile. I must be sure compiler doesn't reorder that call with prior or followed reads and writes.

火乔治
  • 19,950
  • 3
  • 44
  • 60
0xbadf00d
  • 14,584
  • 15
  • 60
  • 93

4 Answers4

40

Marking a member function volatile is like marking it const; it means that the receiver object is treated as though it were declared as a volatile T*. Consequentially, any reference to x or y will be treated as a volatile read in the member function. Moreover, a volatile object can only call volatile member functions.

That said, you may want to mark x and y volatile anyway if you really do want all accesses to them to be treated as volatile.

templatetypedef
  • 328,018
  • 92
  • 813
  • 992
10

You don't have to declare the member variables explicitly..

From Standard docs 9.3.2.3,

Similarly, volatile semantics (7.1.6.1) apply in volatile member functions when accessing the object and its nonstatic data members.

liaK
  • 10,834
  • 10
  • 43
  • 70
8

The following code:

#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;
}

Raises an error upon compilation with 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>

And since a volatile instance can't call a non-volatile method, we can assume that, yes, x and y will be volatile in the method, even if the instance of MyClass is not declared volatile.

Note: you can remove the volatile qualifier using a const_cast<> if you ever need to; however be careful because just like const doing so can lead to undefined behavior under some cases.

ereOn
  • 48,328
  • 33
  • 147
  • 228
  • Correct me if I'm wrong about this, but aren't the semantics of volatile functions like that of const functions in that you can call a volatile function on a nonvolatile object, but not a nonvolatile function from a volatile object? – templatetypedef Jan 28 '11 at 09:47
  • @ereOn- A quick test in `g++` suggests that you can indeed call `volatile` member functions from on-`volatile` objects. The reason that `volatile std::string`s are useless is because if the string itself is `volatile`, it can only call `volatile` member functions, of which there are none. $4.4.1 of the standard clarifies that you can convert a T* to a volatile T* implicitly, and $9.3.1.3 says that the `volatile` qualifier affects the `this` pointer, suggesting that if you have an object of type `T`, the `this` pointer of type `T*` could be converted to a `volatile T*` for the call. – templatetypedef Jan 28 '11 at 09:56
  • @templatetypedef: I reversed the logic (it's only 7am here; I still need some sleep ;)). Thanks, it's now fixed. You can call a `volatile` method from both a `volatile` and `non-volatile` instance. But if your instance is `volatile` you won't be able to call `non-volatile` methods. – ereOn Jan 28 '11 at 09:57
  • @ereOn: So, it is exactly as for `const`, as templatetypedef said. The relevant part is of course not g++, but the standard: Clause 4.4.1 seems to indicate to me that the necessary implicit conversion of `this` from `T*` to `volatile T*` was completely legal. Also note that 9.3.2.4 explicitly says that you can make a call to a cv qualified function if the object expression you invoke it on is “as cv-qualified or less cv-qualified than the member function.” No difference is made between `const` and `volatile` in this area. – Christopher Creutzig Jan 28 '11 at 10:18
  • As for casting: If the original object actually was defined volatile, and you access this object or one of its members as an lvalue (essentially, on the left hand side of an assignment) as something non-volatile, clause 7.1.5.1.7 of the standard says that the program behavior is undefined. Don't do that, even if it works with the current version of your current compiler on your current test data. AFAICS, the cast would be fine for read-only access, just as for `const`. – Christopher Creutzig Jan 28 '11 at 10:26
  • You missunderstood me, I meant: Is it possible to cast a actually non-volatile declared object to a volatile type. Doing the other way is clear to me. – 0xbadf00d Jan 28 '11 at 19:35
3

So using the original example:

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
    } 
};
ianeperson
  • 31
  • 2