24

If I have a C++ method declaration as follows:

class A
{
public:
   double getPrice() volatile;
};
  1. What does volatile represent here?
  2. What could it be used for?

You might be interested in this Dr Dobbs article by Andrei Alexandrescu. I was :)

Edit: That article was written a while back and now it seems that the community has moved on. Herb Sutter has this to say this. Thanks Iain (and Herb!)

@metal points out that Andrei had a follow up article here where he continues to advocate the use of volatile correctness as a valuable tool for detecting race conditions on systems supporting POSIX-like mutexes.

metal
  • 6,202
  • 1
  • 34
  • 49
T33C
  • 4,341
  • 2
  • 20
  • 42
  • This may be a duplicate of http://stackoverflow.com/questions/2444695/volatile-vs-mutable-in-c . – gpcz Feb 24 '11 at 14:54

3 Answers3

17

You're probably familiar with const methods and const-correctness (cf. "Item 15 - Use const proactively" in C++ Coding Standards by Sutter and Alexandrescu), and volatile works in similar but slightly different ways to yield what might be called "volatile-correctness."

Like const, volatile is a type modifier. When attached to a member function as in your example, either modifier (or both!) mean that the object on which the method is called must have or be convertible to that type.

Consider:

struct A
{
  void f();
  void cf() const;
  void vf() volatile;
  void cvf() const volatile;
  // ...
};

void foo( A& a, const A& ca, volatile A& va, const volatile A& cva )
{
  a.f();    // Ok
  a.cf();   // Ok: Can convert non-const    obj to const    obj
  a.vf();   // Ok: Can convert non-volatile obj to volatile obj
  a.cvf();  // Ok: Can convert non-cv       obj to cv       obj

  ca.f();   // Error: can't call non-const method on const obj
  ca.cf();  // Ok
  ca.vf();  // Error: can't call non-const method on const obj
  ca.cvf(); // Ok: Can convert

  va.f();   // Error: can't call non-volatile method on volatile obj
  va.cf();  // Error: can't call non-volatile method on volatile obj
  va.vf();  // Ok
  va.cvf(); // Ok: Can convert

  cva.f();   // Error: can't call non-cv method on cv obj
  cva.cf();  // Error: can't call non-cv method on cv obj
  cva.vf();  // Error: can't call non-cv method on cv obj
  cva.cvf(); // Ok
}

Note these are compile-time errors, not run-time errors, and that is where it's potential usefulness comes in.

Const-correctness prevents unintentional errors at compile-time as well as making code "easier to understand, track, and reason about" (Sutter and Alexandrescu). Volatile-correctness can function similarly but is much less used (note that const_cast in C++ can cast away const, volatile, or const volatile, but rather than calling it cv_cast or similar, it's named after const alone because it is far more commonly used for casting away just const).

For instance, in "volatile - Multithreaded Programmer's Best Friend", Andrei Alexandrescu gives some examples of how this can be used to have the compiler automatically detect race conditions in multithreaded code. It has plenty of explanation about how type modifiers work, too, but see also his follow-up comments in his subsequent column.


Update:

Note that C++11 changes the meaning of const. Thus sayeth the Sutter: "const now really does mean 'read-only, or safe to read concurrently'—either truly physically/bitwise const, or internally synchronized so that any actual writes are synchronized with any possible concurrent const accesses so the callers can’t tell the difference."

Elsewhere, he notes that while C++11 has added concurrency primitives, volatile is still not one of them: "C++ volatile variables (which have no analog in languages like C# and Java) are always beyond the scope of this and any other article about the memory model and synchronization. That’s because C++ volatile variables aren’t about threads or communication at all and don’t interact with those things. Rather, a C++ volatile variable should be viewed as portal into a different universe beyond the language — a memory location that by definition does not obey the language’s memory model because that memory location is accessed by hardware (e.g., written to by a daughter card), have more than one address, or is otherwise 'strange' and beyond the language. So C++ volatile variables are universally an exception to every guideline about synchronization because are always inherently “racy” and unsynchronizable using the normal tools (mutexes, atomics, etc.) and more generally exist outside all normal of the language and compiler including that they generally cannot be optimized by the compiler.... For more discussion, see my article 'volatile vs. volatile.'"

metal
  • 6,202
  • 1
  • 34
  • 49
  • Thanks for the link to the subsequent column. I have edited my question to include it. – T33C Feb 24 '11 at 15:50
12

It is a volatile member which, just like a const member can only be called on const objects, can only be called on volatile objects.

What's the use? Well, globally volatile is of little use (it is often misunderstood to be applicable for multi-threaded -- MT -- programming, it isn't the case in C++, see for instance http://www.drdobbs.com/high-performance-computing/212701484), and volatile class objects are even less useful.

IIRC A. Alexandrescu has proposed to use the type checking done on volatile objects to statically ensure some properties usefull for MT programming (say that a lock has been taken before calling a member function). Sadly, I don't find the article back. (Here it is: http://www.drdobbs.com/184403766)

Edit: added links from the comments (they where added also in the question).

AProgrammer
  • 51,233
  • 8
  • 91
  • 143
  • Do you know of any good resources on why `volatile` shouldn't be used for MT? – Pedro d'Aquino Feb 24 '11 at 15:04
  • I edited my question to include the article by Andrei to which you refer. I wrote this question in response to a previous question about const by another member and thought this question would be good follow on – T33C Feb 24 '11 at 15:10
  • Papers about the memory model by Boehm and others on the committee site describe this. – AProgrammer Feb 24 '11 at 15:11
  • 3
    @Pedro re volatile and MT see http://herbsutter.com/2009/01/12/effective-concurrency-volatile-vs-volatile/ – iain Feb 24 '11 at 15:13
  • @T33C, it is so old? Time flies. Note that Andrei mention in this article that volatile per se is related to threads. I don't think he would now. – AProgrammer Feb 24 '11 at 15:14
  • Herb's paper pointed by iain is in line with my understanding. – AProgrammer Feb 24 '11 at 15:22
  • I am unable to read Herb's article. Work proxy filters it. Thanks for all the comments. I was blown away by Andrei's article because I had never considered a volatile method. – T33C Feb 24 '11 at 15:38
  • @T33C, the blog is mostly to refer to: http://www.drdobbs.com/high-performance-computing/212701484 – AProgrammer Feb 24 '11 at 15:45
  • The Alexandrescu article is at: http://www.ddj.com/cpp/184403766;jsessionid=URZPZDHYE0HWLQE1GHOSKHWATMY32JVN – user122302 Feb 24 '11 at 18:51
  • Thanks for the interesting comments everyone. Because this answer led to the comments I am selecting it as the answer plus it got the most votes. – T33C Feb 25 '11 at 10:05
  • IMO it would make sense if `volatile` would prevent method from being inlined. I really miss counterpart to `inline`. – mip Jan 14 '17 at 21:45
  • Since this is the accepted answer, I'd suggest at first use of the acronym "MT" be spelled out as "Multi Threaded (MT)". A google search for "MT programming" gives no hint to one unfamiliar with the acronym in this context. – erco Mar 20 '20 at 16:36
  • @erco, you can edit the answer, that's the stackoverflow way. – AProgrammer Mar 21 '20 at 16:00
5

In member functions (the only functions that can have cv-qualifiers), the const or volatile effectively modifies the this pointer. Therefore, like a const member function can access the object only as if through a const pointer, a volatile member function can access the object only as if through a volatile pointer.

The informal meaning of volatile is that an object can change due to circumstances outside the program (such as memory-mapped I/O or shared memory). The precise meaning is that any access to volatile data must be done in reality as it is written in the code, and may not be optimized out or changed in order relative to other volatile accesses or I/O operations.

What this means is that any operations relating to the object in volatile member functions must be done in order as written.

Further, a volatile member function can only call other volatile (or const volatile) member functions.

As for what use it is...frankly, I can't think of a good use right now. volatile is vital for some data objects, such as pointers pointed to I/O registers, but I can't think of why a volatile member function would be useful.

David Thornley
  • 56,304
  • 9
  • 91
  • 158