[LC++]enum, #define, const, static const, or member const???

Mark Phillips mark at austrics.com.au
Fri Apr 5 20:39:05 UTC 2002

Thanks for your very helpful reply!

Carlo Wood wrote:

>Mark Phillips wrote:
>>So as you can see, there are a miriad of different ways I could do this.
>>Can anyone give some guidance about which is best?  Or failing this, the
>>advantages and disadvantages of the different methods?
> 1) Just use an integer
> Bad idea, only do this the values are restricted to two values
> (0 and 1; or -1 and 0), or to an infinite number of values
> that can be devided into two or three 'kind' of groups, for
> example: < 0, == 0, and > 0.  Where the actual value of the
> int also has a meaning.  Not however that in that case you
> are still not typing the literal number 2 (3, 4, ... etc).

But why bad?  My guess is because in C++ there is no way of
saying "this is a special type of integer".  The way around this
would be to do something like:

enum ShortRange {
   srPredex=-1, srDeb=0,
   srZero=0, srOne=1, srTwo=2,
   srFin=2, srPodex=3};

Then you effectively get a subrange of the integers, with the
advantages you mention above, __and__ you get your own separate
type.  (The values srZero, srOne and srTwo are the "normal usage
values", whereas srPredex and srPodex are "only to be used in special
circumstances, like with index variables".)

Below you seem to say that this method is good except not very
maintainable.  Why?  Suppose I wanted to extend it to include
-1 and 3 as "to be used" values.  I would just do:

enum ShortRange {
   srPredex=-2, srDeb=-1
   srMiOne=-1, srZero=0, srOne=1, srTwo=2, srThree=3,
   srFin=3, srPodex=4

And as all for loops etc would be defined in terms of srPredex,
srPodex, srDeb and srFin (possibly also in terms of srZero),
code using these would not have to change.

(By the way, "predex" is short for "pre-index-set", "podex" is short
for "post-index-set", "deb" is short for "debut index", and "fin" is
short for "finale index".  Whereas srPredex and srPodex should be
thought of as "special" elements distinct from the usual range,
srDeb and srFin are simply alternative labels for the first and last
elements respectively of the usual range.)

> 2) Using macros for a constant
> Never do that.

Why not?  Is it because the compiler is given no type
information and may have limited opportunity for checking?
...whereas doing

int const myConstant=6;

does everything a #define does, but does type checking
as well.

> 3) Using enums
> This is the ideal way if it is possible, in your case it is.
> Advantages:
> - The code becomes more readable (use clear names!).
> - While debugging (gdb) you will also see the names of
>   the enums.
> - You can't make typos without the compiler complaining.
> - It is easy to extend without getting confused or
>   forgetting to update parts of your code.
> - You are told when you forget a value in a switch.

I tested this with gcc.  It didn't tell me --- and I
even had "-Wall" selected!

> Disadvantages:
> - If the kinds have more grouping in common it is not
>   really supported to the actual value of the enums
>   to compare (ie, < 0, == 0, > 0).  You can assign the
>   integer values to the enums but it becomes less
>   maintainable.
> - You can't have a group like mentioned in the previous
>   point with an infinite number of members.
> - You can't treat the values also as integers (ie, array
>   index) because that is very dangerous and you are not
>   allowed to do arithmetics in certain cases.

With the setup I used with my "ShortRange" type, surely it
would be safe to use them like integers?

> When you run into the disadvantages then you want to use
> a integer constant.
> 4) Using 'int const'
> In all cases where you also use the actual integer
> value of the constants.
> Disadvantage: you don't see the names in gdb and you
> are not told if you forget a value in a switch.
> Advantage: you don't have the disadvantage of enums
> while still having the advantages 'code becomes more readable'
> 'You can't make typos without the compiler complaining' and
> 'It is easy to extend without getting confused or forgetting
> to update parts of your code.'
> A minor disadvantage is that when you need the values
> in more than one compilation unit (source files) then
> you can't make the values static, 

Why not?  Each compilation unit has its own static constant value.
Provided it's address is not asked for, no storage need be
allocated for it.

Did you mean to say "... (source files) then it's better
not to make the values local."?  I'm not sure I fully understand.

> poluting global namespace
> (but that also holds for the enum).  However, when you
> put the constants in a header file then you get linker
> collisions so you need to put them as 'static int const'
> in header files, causing them to appear in every compilation
> unit seperately or you'd use 'extern' declarations in a
> header file, but then they aren't really constants anymore
> (no optimization).

> 5) Using 'static int const'
> Doesn't polute the global namespace.  You want this when
> the values are completely related to that particular
> class (as in your case).  The enum definition should also
> be put inside the class for the same reason: not to polute
> global namespace (I'd even make it private when possible).

Isn't "static int const" equivalent to "int const"?  Ie doesn't
the latter default to static?



More information about the tuxCPProgramming mailing list