const && volatile = ???

Started by
10 comments, last by Nypyren 16 years, 12 months ago
Hey I am studying C/C++ and ran into a section where I read about the const and volatile keywrods. I have a very vague understanding of why I would use them, but I was hoping you all could give me your impressions of them and when or where a good place would be to use them. I am learning C/C++ to eventually program games, so if you could provide examples in an 'RPG' nature, that would be great. From my limited understanding, const means the variable doesn't change, 'which allows the compiler to perform extra optimizations'. The volatile keyword means the variable could change at any time, so C++ shouldn't spend time trying to 'optimize away multiple reads of the flag'. Ok so anyone care to explain that to someone who has no idea what they just read? Are const and volatile global variables, or file spacific, or when/why would I want to use them? Thanks so much if you can help me understand these. BUnzaga
Advertisement
Quote:Original post by BUnzaga
Hey I am studying C/C++ and ran into a section where I read about the const and volatile keywrods.

I have a very vague understanding of why I would use them, but I was hoping you all could give me your impressions of them and when or where a good place would be to use them.

I am learning C/C++ to eventually program games, so if you could provide examples in an 'RPG' nature, that would be great.

From my limited understanding, const means the variable doesn't change, 'which allows the compiler to perform extra optimizations'. The volatile keyword means the variable could change at any time, so C++ shouldn't spend time trying to 'optimize away multiple reads of the flag'.

Ok so anyone care to explain that to someone who has no idea what they just read? Are const and volatile global variables, or file spacific, or when/why would I want to use them?

Thanks so much if you can help me understand these.

BUnzaga

They are type qualifiers. You attach them to the definition/decleration of an instance of a type to qualify if the type will be const, volatile, or const volatile.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

Const and volatile, while occupying a common grammatical niche, have absolutely nothing to do with each other. Other than where they appear relative to a variable, don't even try to compare them; it confuses the issue. Const is used to guarantee that a function will not attempt to change a particular piece of data. Volatile is used to indicate to the compiler that other threads may access a shared memory area. Don't try to understand them together, because they are different things.
an example of a volatile value would be the value of a register in a network card that says how many bytes are pending in the input buffer. Even though the program you are writing doesn't change the value (and the compiler can see this because it knows the code it has), the value may change anyway ... bytes come in across the network and the value changes ... so the value reference to at that address is marked "volatile" so that if you have code like this:

while(!done)
{
if(bytesInBuffer != 0)
{
ProcessBytes();
}
}

the compiler will actually read the value of bytesInBuffer out of memory each time through the loop, and not optimize it to just check the value once, and never check it again since the compiler thinks it cannot change. volatile should also prevent the value from being read from non-shared cache in a multi-core computer, since it also may have been changed by the other core.
----
volatile is almost never used in a normal program ... period. You could write a million lines of code and never ever need it. I have used it because I have worked on writing IO drivers for devices (like a USB AM/FM tuner, and a console IO harness), but normal code simply doesn't use the volatile keyword in general.

const on the other hand is used all the time, by every good programmer in every program longer than a few thousand lines of code. It is mainly to tell other programmers that a value will not be modified (by some other thing).

So if I download someones library that has a function like this:

Point3D Midpoint(const Point3D &point1, const Point3D &point2);

I know that when I pass my 2 variables to the Midpoint function, it won't change their values ... because the are marked as "const" so the function doesn't change them.

So if I have code like this:

Point3D a(0.0, 0.0, 0.0);
Point3D b(20.0, 40.0, 50.0);
Point3D c = Midpoint(a, b);

I would expect c to be (10.0, 20.0, 25.0);
and a and b to be exactly the same after the function as before ...
Forget volatile for now. You will probably never need it unless you're doing quite low level stuff.


Read up on const correcness.

const is great. It usually doesn't actually let the compiler make too many optimisations, but it makes your code a lot safer. It lets you have some parts of the code treat an object as "read only", so those parts of the code can look at the data, but not make any changes.

e.g. In this example, the NPC class has a collection of items. You can ask an NPC how many items it has, and ask to look at each item.
The Item class has a name that you can get and set.

The "DoesNPCHaveItem" function takes a const reference to an NPC and the name of the item. It determines if the NPC has an item with this name. To do this it doesnt need to make changes to the input string or the NPC, which is why I use a *const* reference. Doing this makes sure that even if I try, this function cannot make any changes to the NPC, it can only inspect it.
class Item{public://this function returns a *const reference* to a string, which means the return value is actually an alias to m_name, but you can't actually edit m_name because the reference to it is const'ified.//the const after the parenthesis means this function is a *const function*//   that means this function can be called on a "const Item&" or "const Item*"   const std::string& GetName() const { return m_name; }//this is not a const function, so you must have a "Item&" or "Item*" to call this one!   void SetName(const std::string& n) { m_name = n;    }private:  std::string m_name;};class NPC{public:  int  GetNumberOfItems() const;//this function is used in the example function below because we have a "const NPC&" - so only *const functions* can be called.  const Item& GetItem( int ) const;//this function is not called in this example  Item& GetItem( int ); };bool DoesNPCHaveItem( const NPC& npc, const std::string& name ){  for( int i=0, i<npc.GetNumberOfItems(); i++ )  {    if( npc.GetItem(i).GetName() == name )    {      return true;    }    //N.B. npc.GetItem(i).SetName("Fred"); would give you a compile error, because it is not a const function! (npc.GetItem returns a "const Item&", so only the const functions inside Item can be used)  }  return false;}
Uses of Const in C++:

1) Const can be used to define compile time constants. These are generally global, often defined in header files and usually written in The following format:
const int COMPILE_TIME_CONSTANT=0;
Compile time constants like this serve as type safe alternatives to macros. They can be primitive types or objects.

2) Class level static constants. These are also to compile time constants, but are defined inside a class. They are written the same way, but accessed through there class. For example:
class MyClass{    private:         static const int CLASS_CONSTANT=1;}


3) Class instance constants; Non static class level constant variables. These are rare. These have can be initialized in the initialization list of a class constructor, but cannot be subsequently changed. For example:
class MyClass{    private:         const int classID;    public:        MyClass(int iD)classID:int(iD){}}


4) const references and pointers. These are references and pointers that promise not to change the object the refer or point to. These are most often used as arguments. For example:
const char *func(const MyClass &myClassObject,const MyClass *myClassObject);

It is good style to make use of const in function arguments as above. They can also be used in class member, or inside functions.
In the case of pointers, const modifies the whatever comes right before the key word, unless it is the first, in which case it modifes the object. For example:
const int **ptr1;//a pointer to an array of constant integers.int const **ptr2;//Same as above.int const * const * pt2;//a pointer to a constant array of constant integers;int **const pt2; // an unmodifiable pointer to a nonconstant array of integers.

The last of these cases is rarely used, but the others should be used whenever possible.

5) const return values. These are a special case of the above. When a function returns a const object reference or pointer, it tells whatever other function is making the function call that it is not to try to modify the value pointed to or referenced. It is possible to get around this easily, so the const in this case serves more as a signal to the programmer than as an actual constraint.

6) const methods: methods that promise not to modify the object that they are a part of. More technically, they promise not to modify non-mutable members of the object. The syntax is like this:
class MyClass{    private:        int member;        mutable int accesses;    public:        int getMember() const{++accesses; return member;}}

It is good style to use these whenever possible.



BTW you should pick a language an stick to it. C and C++ are very different languages with very different paradigms, or approaches to programming.

[Edited by - King Mir on April 20, 2007 1:50:12 AM]
I think I am starting to get it. So far Xai's example has made the most sense to me. I am just starting out so I can jumble through the lines of code, but only some of it translates to stuff I understand.

I do plan to get into multi-user and games that have servers eventually. Is this a situation where I would encounter a use for volatile variables?

As far as the const keyword. I understand that it makes a 'non changable' variable, but a variable won't get changed unless you code it to be changed, so I don't really understand why I would have to have these fail safes in store unless I plan to be really sloppy with when or how I assign information.

I have to admit I haven't used C++ indepth yet, but I have some little experience with &#106avascript and I have programmed probably about 1500 lines of code in a tetris clone in &#106avascript, and I never used const there.<br><br>I just said something like:<br><pre><br>var median=15; //width of cube<br></pre><br><br>Then I would use 'median' when I wanted to do cube length calculations, and as long as I didn't make a mistake the value for 'median' would always stay 15.<br><br>Like in your example Xai:<br><!--QUOTE--><BLOCKQUOTE><span class="smallfont">Quote:</span><table border=0 cellpadding=4 cellspacing=0 width="95%"><tr><td class=quote><!--/QUOTE--><!--STARTQUOTE--><i>Original post by Xai</i><br><br>Point3D Midpoint(const Point3D &point1, const Point3D &point2);<br><br>Point3D a(0.0, 0.0, 0.0);<br>Point3D b(20.0, 40.0, 50.0);<br>Point3D c = Midpoint(a, b);<br><br>I would expect c to be (10.0, 20.0, 25.0);<br><!--QUOTE--></td></tr></table></BLOCKQUOTE><!--/QUOTE--><!--ENDQUOTE--><br><br>Even if '&point1', '&point2' for the 'Midpoint' function weren't declared as const, I would expect 'a' and 'b' to be the same, because they weren't modified right? &point1 is a refrence to the value in 'a', isn't it? Since we don't ever say a=somthing, a is never changed. So is it just to be idiot proof?<br><br>All this might make more sense when I get further into classes, and several different .cpp files, .dlls and stuff.<br><br>I think I have a better understanding for now though, thanks for the examples, and if you have any new ideas, or how to relate them to games, I'd apprecate it.
Quote:As far as the const keyword. I understand that it makes a 'non changable' variable, but a variable won't get changed unless you code it to be changed, so I don't really understand why I would have to have these fail safes in store unless I plan to be really sloppy with when or how I assign information.


Const isn't so much for you - you know what the code does - but for other people. Often you will be using code, and you only have accessors to the headers(or perhaps you do have access to the source and don't want to take the time to look it up). If you see a function declaration like:

void processData( const int* data );

...you know that the function will process the data but not change it. This is really helpful to know. Equally, imagine if the string copy declaration looked like this:

void strcpy( char*, char* );

What gets copied to where? You've have to look it up in the docs or open the header file. Thanks to const, actually it looks like this:

void strcpy( char*, const char* ); // NOTE - I think it returns void anyway, not certain but that's not the point of this!

...so you know that the first argument must be the destination (as it changes), and the second argument must be the source (as it does not).

Const is therefore immensely valuable for writing code that either (a) other people will use or (b) you will use later when you might have forgotten the precise details of how you wrote the function - you can't keep a million different functions in your head. Because it's so valuable in those situations, you'll (hopefully!) soon find yourself using it even when (a) and (b) probably don't apply.
Additional:

Quote:Then I would use 'median' when I wanted to do cube length calculations, and as long as I didn't make a mistake the value for 'median' would always stay 15.


Yeah, as long as you don't make a mistake. Declare it const and you are unable to make a mistake - the compiler won't let you.
People have discussed const pretty well - you're right to think that it's not strictly necessary if you are a perfect programmer, but it exists as a way to prevent making mistakes. Remember compile errors are many times easier to fix than runtime and logic errors - const is a way of making some logical errors show up as syntax errors saving you the trouble of tracking them down.

Volatile is as people have said not amazingly common and one of those keywords where you'll know when you need it. Understanding why it's important requires knowing some computer architecture, but basically it works like this. Your CPU has a number of registers - storage areas built into the CPU that it performs operations on. Generally data is moved from memory into a register, operated on, then written back to memory (ok so that was a HUGE simplification but it gets the point accross). Now memory is slow and registers are fast, so if you write:

int accum=0;for(int i=0; i<5; i++)   accum+=i;

The compiler might put i and accum in registers and not write them till memory until after the loop. This would make the program a lot faster.

However under certain circumstances things in memory can change without your code changing them. Volatile is used for some of the circumstances. Usually it's used when a piece of hardware is mapped into main memory. For example a number representing the last key pressed on your keyboard might be stored to 0x10000. In this case the value in memory is changing WITHOUT your program being aware. If you're examining such a variable in a tight loop the compiler might not be reading it from memory and instead storing it in a register. This would be bad if you are waiting for the value to change as a result of keyboard input. Volatile tells the compiler NOT to store the variable in a register but to read it from main memory every time.

As alluded to in my explanation this is almost always used for VERY low level hardware handling and is something you will probably never run accross in normal programming. You alluded to multi threading in your post about multi-player servers. While multi-threading is another example of values in memory changing without a particular thread being aware of it, it's not really a situation where volatile is applicable. I'm not going into proper multi-threading here because it's complicated and I don't claim to be an expert. Safe to say you should not be using volatile variables as a way to write synchronized multi-threaded code.

This topic is closed to new replies.

Advertisement