tags:

views:

2294

answers:

6

I always mess up how to use it correctly. Is there a set of rules defining what you can and cannot do?

I want to know all the Do's and all DoNOTs in terms of assignments, passing to the functions, etc.

Thanks

+64  A: 

Read it backwards...

  • int* - pointer to int
  • int const * - pointer to const int
  • int * const - const pointer to int
  • int const * const - const pointer to const int

Now the first const can be on either side of the type so:

  • const int * == int const *
  • const int * const == int const * const

If you want to go really crazy you can do things like this:

  • int ** - pointer to pointer to int
  • int ** const - a const pointer to a pointer to an int
  • int * const * - a pointer to a const pointer to an int
  • int const ** - a pointer to a pointer to a const int
  • int * const * const - a const pointer to a const pointer to an int
  • ...

And to make sure we are clear on the meaning of const

const int* foo;
int *const bar; //note, you actually need to set the pointer 
                //here because you can't change it later ;)

foo is a variable pointer to a constant int. That is you change what you point to but not the value that you point to. Most often this is seen with cstrings where you have a pointer to a const char. You may change which string you point to but you can't changed the strings content. This is important when the string itself is in the data segment of a program and shouldn't be changed.

bar is a const or fixed pointer to a value that can be changed. This is like a reference with out the extra syntactic sugar. Because of this fact, usually you would use a reference where you would use a T* const pointer unless you need to allow null pointers.

Matt Price
I would like to append a rule of thumb which may help you remember how to discover whether 'const' applies to pointer or to pointed data: split the statement at asterix sign, then, if the const keyword appears in the left part (like in 'const int * foo') - it belongs to pointed data, if it's in the right part ('int * const bar') - it's about the pointer.
Michael
@Michael: Kudos to Michael for such a simple rule for remembering/understanding const rule.
ShaChris23
Neat answer, I guess this (http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.5) makes it clear :)
legends2k
+1  A: 

Rule is "const" apply to what preceed it immediately. Exception, a starting const applies to what follow.

  • const int* is the same as int const* and means "pointer to constant int".

  • const int* const is the same as int const* const and means "constant pointer to constant int"

Edit: for the do and don't, if this answer isn't enough, could you be more precise about what you want?

AProgrammer
+1  A: 

Simple Use of ‘const’

The simplest use is to declare a named constant. To do this, one declares a constant as if it was a variable but add ‘const’ before it. One has to initialise it immediately in the constructor because, of course, one cannot set the value later as that would be altering it. For example,

const int Constant1=96;

will create an integer constant, unimaginatively called ‘Constant1’, with the value 96.

Such constants are useful for parameters which are used in the program but are do not need to be changed after the program is compiled. It has an advantage for programmers over the C preprocessor ‘#define’ command in that it is understood & used by the compiler itself, not just substituted into the program text by the preprocessor before reaching the main compiler, so error messages are much more helpful.

It also works with pointers but one has to be careful where ‘const’ to determine whether the pointer or what it points to is constant or both. For example,

const int * Constant2

declares that Constant2 is variable pointer to a constant integer and

int const * Constant2

is an alternative syntax which does the same, whereas

int * const Constant3

declares that Constant3 is constant pointer to a variable integer and

int const * const Constant4

declares that Constant4 is constant pointer to a constant integer. Basically ‘const’ applies to whatever is on its immediate left (other than if there is nothing there in which case it applies to whatever is its immediate right).

ref: http://duramecho.com/ComputerInformation/WhyHowCppConst.html

ufukgun
+3  A: 

Like pretty much everyone pointed out:

[18.5] What's the difference between "const Fred* p", "Fred* const p" and "const Fred* const p"?

You have to read pointer declarations right-to-left.

  • const Fred* p means "p points to a Fred that is const" — that is, the Fred object can't be changed via p.
  • Fred* const p means "p is a const pointer to a Fred" — that is, you can change the Fred object via p, but you can't change the pointer p itself.
  • const Fred* const p means "p is a const pointer to a const Fred" — that is, you can't change the pointer p itself, nor can you change the Fred object via p.
luke
+5  A: 

I think everything is answered here already, but I just want to add that you should beware of typedefs! They're not just text replacements. For example:

typedef char *ASTRING;
const ASTRING astring;

The type of astring is char * const, not const char *. This is one reason I always tend to put const to the right of the type, and never at the start.

Kaz Dragon
+2  A: 

This question shows precisely why I like to do things the way I mentioned in my question is const after type id acceptable?

In short, I find the easiest way to remember the rule is that the "const" goes after the thing it applies to. So in your question, "int const *" means that the int is constant, while "int * const" would mean that the pointer is constant.

If someone decides to put it at the very front (eg: "const int *"), as a special exception in that case it applies to the thing after it.

Many people like to use that special exception because they think it looks nicer. I dislike it, because it is an exception, and thus confuses things.

T.E.D.
I'm torn on this issue. Logically it makes sense. However most c++ developers would write `const T*` and it has become more natural. How often do you ever use a `T* const` anyways, usually a reference will do just fine. I got bit by all this once when wanting a `boost::shared_ptr<const T>` and instead wrote `const boost::shared_ptr<T>`. Same issue in a slightly different context.
Matt Price
Actually, I use constant pointers more often than I use constants. Also, you have to think about how you are going to react in the presence of pointers to pointers (etc.) Admittedly those are rarer, but it would be nice to think about things in a way where you can handle these situations with applomb.
T.E.D.