7

I asked this function based on this concept (maybe incorrect?!): Wherever a const can exist, a volatile can exist at the place.

class classA
{
public:
    const int Foo() const;
}

Here the first "const" means the return value is const, we can not change it. the second const means "Is Query", this function can not change the member variable and can not call non-const function.

Now comes to volatile: I can understand what volatile does on a variable, like "volatile int a;" However I have no idea of the difference among the following:

Case 1: The return type is volatile?
volatile void Function1();

Case 2: The function can only call volatile functions? Why add volatile here? Any example?
void Function2() volatile;

Case 3:   Is it valid? If yes, is it simply a combination of Case 1 and Case 2?
volatile void Function3() volatile;

When we put the const at the end of function declaration, it has a beautiful name: "Is Query" Can you give a decent name/alias to the "volatile" in Case 2? I mean, whenever we call this name, we can know we are talking about Case 2, not case 1.

Thank you in advance!

milesma
  • 1,561
  • 1
  • 15
  • 37
  • volatile is simply a hint for the optimizer that it cannot trust the variable to have the value assigned to it won't make bad assumptions. Use it only with multithreaded code. – Daniel Oct 04 '11 at 05:17
  • I've seen 'volatile' on methods used incorrectly - beware that marking a method as such does *nothing* to the ordering of the the method itself, or how it behaves. I had to fix a bunch of code recently where the author thought it basically turned off the optimizer. It's just type checking - as in, the method is allowed to be called on volatile instances of the object. This is usually bad practice. – John Ripley Oct 04 '11 at 05:20
  • @Dani: that's wrong in far too many ways to explain in a single comment. Check the "related" section at the right >>> – MSalters Oct 04 '11 at 07:17
  • For an interesting (ab)use of `volatile` qualification to member functions, read [this](http://stackoverflow.com/questions/2491495/may-volatile-be-in-user-defined-types-to-help-writing-thread-safe-code) related question. Before doing so, beware: the article only uses the compile time checks that John Ripley mentions above, it *does not* use `volatile` for anything else, and in particular it does not use *volatile semantics* for any guarantee that it might or not provide to multithreaded code. – David Rodríguez - dribeas Oct 04 '11 at 08:09

3 Answers3

7

Volatile has one primary function, which is to say "STOP! This object is connected to external resources, and thus when I write to it, don't reorder the write with respect to other volatile reads or writes, and when I read to it, don't reorder it likewise and don't optimize these away!".

To support this, you can put volatile after member functions, which is necessary to call member functions on volatile class objects.

// just a silly example
struct HWOverlayClock {
  HWOverlayClock() { }

  int64_t getTime() volatile const { return timestamp; }

  int64_t timestamp;
};

// imagine we use an implementation defined way to put the
// object at some fixed machine address
volatile const HWOverlayClock clock __attribute__((at_address(0xbabe)));

Putting volatile on a return value can be done too, but it seems to me that it would be less useful since return values are usually temporaries and volatile semantics are quite on the the opposite scale of temporaries. Putting volatile on void is particularly nonsensical (const and volatile are ignored if put at the top-level of a return type if the type is not a class type (i.e at the right of a * if it is a pointer), because these return values do not correspond to memory, likely being kept in registers by implementations too). Putting volatile on non-toplevel for references or pointers can be useful, like in the following

struct Controller {
    HWOverlayClock volatile const* getClock() const { return clock; }

private:
    volatile const HWOverlayClock *clock;
};

Hope it helps.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Wouldn't it be "cleaner" to say `volatile const HWOverlayClock *clock = (volatile const HWOverlayClock *)0xbabe;` than to "use an implenetation defined way" to do the same thing? Perhaps with a little more work we can make `clock` a reference instead of a pointer. – Chris Lutz Oct 04 '11 at 05:39
  • 1
    @Chris in real code perhaps I would use such a pointer cast. However keep in mind that you need implementation defined abilities in any case, because the implementation deems whether the object located at `0xbabe` is `volatile` or not (and whether there is an object at that address at all), depending on which it may optimize or not. Using `__attribute__` we just make the dependency explicit. Only for the sake of exposition (for showing a volatile member function) I did choose this way :) – Johannes Schaub - litb Oct 04 '11 at 05:44
3

The second const means "Is Query", this function can not change the member variable and can not call non-const function.

Yes, thats correct.

volatile void Function1();
The return type is volatile?

The return type of the function here is void(means nothing). If it returns nothing, it makes no sense to specify that the nothing being returned be volatile. The volatile preceeding void will be reduntant.

If the return type was int, then yes the volatile preceeding it applies to the return type. It means that this return value can only be taken in a variable type which is volatile.

void Function2() volatile;
The function can only call volatile functions? Why add volatile here? Any example?

Yes, thats correct. See the Code Example below which demonstrates this.

volatile void Function3() volatile;
Is it valid? If yes, is it simply a combination of Case 1 and Case 2?

The volatile in Case 1, is redundant, If a function is returning void(nothing) it makes no sense that the returned value be volatile, So essentially above is equivalent to just case 2.

An sample Example:

#include<iostream>

class Myclass
{
    public:
        volatile int i;
        Myclass():i(10){} 
        void doSomething()
        {
            std::cout<<"\nInside doSomething";
        }
        void doSomethingMore() volatile
        {
            std::cout<<"\nInside doSomethingMore";
            doSomething();   //Error


        }

};

int main()
{
     Myclass obj;
     obj.doSomethingMore();

     return 0;
}

"Is Query" Can you give a decent name/alias to the "volatile" in Case 2? I mean, whenever we call this name, we can know we are talking about Case 2, not case 1.

Follow the simple rule:
Whenever the volatile or the const keywords appear at the end of the function signature in declaration or definition the keyword applies to the function.

This is because anything that preceeds the function signature applies to the return type.

It make more sense to use the volatile keyword preeceding the function signature because it exactly indicates the purpose, I think you should stick to this standard way because it demonstrates the intent more clearly than any alias would.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • const and volatile are not the same at any case. – Daniel Oct 04 '11 at 05:19
  • The last paragraph is a bunch of nonsense. Put `const` or `volatile` (or both) after the parameter list if you mean for them to apply to the `this` pointer, and at the beginning of the signature if you want them to apply to the return type. "indicates the purpose" and "demonstrates the intent" has nothing to do with it, it isn't a matter of style but semantics. – Ben Voigt Oct 04 '11 at 14:24
3

the second const means "can be used when this is a pointer to const", this function can not change non-mutable member variables of this and can not call non-const functions on this.

There, fixed that for you.

Now it should be clear what a volatile member function means: it can be called when this is a pointer to volatile. The requirement that it can only call other member functions if they also are volatile is a consequence, but not the core meaning.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720