tags:

views:

921

answers:

7

I am trying to define a constant BUFFER_LENGTH for my class for a given usecase.

//1. Using preprocessor declaration
//#define BUFFER_LENGTH  12

//2.Global constant
//const int BUFFER_LENGTH  = 12;
class MyRequest
{
public:
    //3. Define an in-class constant
    //static const int BUFFER_LENGTH = 12;

    //4. Declare an enum constant
    enum 
    {
     BUFFER_LENGTH = 12
    };

    MyRequest()
    {
     strcpy(mBuffer, "TestString");
     printf("Buffer: %s, BUFFER_LENGTH = %d",mBuffer, BUFFER_LENGTH);
    }
private:
    char mBuffer[BUFFER_LENGTH];
};

I just listed down the different ways in which constant can be defined for the class.

1. Using Preprocessor constant
2. Using Global constant
3. Using in-class constant
4. using an enum.

Out of these, which is the best approach to define the constants for the given use case? I prefer to use the enum constant over others approaches. Is there any other better approach which I have missed out.

Thanks,

+7  A: 

An enumerate type is not meant to define a numeric constant, though it's (ab)used for that a lot in template-metaprogramming.

If the constant's meaning is entangled with the class, I would define it in there. Then you're still having two choices:

 class WithConst {
 public:

     // 1. as a const static member variable
     static const int sc_nNumber = 100; // I can initialize here for
                                        // integral-types only

     // 2. as a static member function - possibly inlined.
     static int sf_nNumber() { return 100; }
 };

The plus-side of the second choice is that you don't need to alter any client code later when you want to e.g. read the constant out of the registry, or a config file.

xtofl
The second example is not a "constant integral expression" under the current rules of the standard and so cannot be used for example as an array index.
Richard Corden
That's indeed a drawback.
xtofl
You'll have to wait a bit before static constexpr int sf_nNumber() { return 100; } is a valid const expression.
Eclipse
@Josh: indeed! C++0x defines the 'constexpr' keyword to annotate this. (somehow it rang a bell)
xtofl
+7  A: 

It is always better for maintenance purposes to restrict the scope of any name (be it function, variable or constant) as much as possible. So I would suggest either

static const int BUFFER_LENGTH = 12;

or

enum { BUFFER_LENGTH = 12 };

inside the class definition.

There isn't much benefit to the former, except that you can explicitly control the type. enum causes C++ to choose an unspecified integral "underlying type" for you -- it could be as small as char if your enum contains only small values, though empirically, most compilers by default will use an int.

j_random_hacker
+3  A: 

The static const member variable is the best - it's concise, solves the problem completely and guarantees that no conflicts will occur with other similar classes (that is quite possible with preprocessor definition or global constant). I suggest that you declare it in CamelCase rather that in all capitals with undescores so that it doesn't look as something special but as a normal class member which it really is.

sharptooth
+2  A: 

I read in "Thinking in C++" that the "enum-hack" was used in the past, because some compilers didn't support "static const" class members :
http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter08_023.html

So if you are using an antique compiler, or want to support them use the enum-hack. (I have no idea HOW old they must be to not support static const)

qwerty
I have VC 6 compiler. I *doesnot* support static const class memebers!
aJ
+1  A: 

I'm not sure if they are completely interchangeable in this specific case. Since you are basing the size of an array member on the constant, I believe that it has to be an enumerated value. I don't have the time to look it up in the Standard, but I would be surprised if you can use an int member as an array size even if it is static const since the actual value might not be visible in the header.

// === in myclass.h
class MyClass {
public:
    static const int MY_SIZE;
private:
    int ary[MY_SIZE];
};

// === in myclass.cpp
/*static*/ const int MyClass::MY_SIZE = 10;

// === in otherclass.cpp
void OtherClass::operation(MyClass& obj) {
    std::cout << "Sizeof(MyClass) = " << sizeof(obj) << std::endl;
}

I don't think that the compiler can compile otherclass.cpp without having already compiled myclass.cpp.

In most other cases, I would say Go with the class static constant option since it will participate a little more intelligently in type deduction and such. I only use enumerated integer constants when I really need to or when they are truly enumerated constants (of course).

Edit

I just took a look at the Standard whilst I was munching away on lunch (Thanks for the nudge David)

An integer constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and sizeof expressions.

It looks like the constant and enum will both work provided that you provide the constant initializer in the declaration (or is that definition?).

D.Shawley
In standard C++, a const int is a compile-time constant, and may be used as such. You have to initialize on declaration.
David Thornley
+1  A: 

Using const int can be less efficient than using enum, below is a program that demonstrates this. Compiled with Metrowerks CodeWarrior 8.x for Windows, it shows that an object of a class that defines a constant as const int takes 4 bytes of memory more than a similar class that defines this constant as enum:

#include <stdio.h>
#include <stdlib.h>

class foo {
    enum { MY_CONST = 1 };
    int x;
    public:
    foo();
};
class bar {
    const int MY_CONST;
    int x;
    public:
    bar();
};

int main() {
    printf( "%u %u\n", sizeof( foo), sizeof( bar));
    return EXIT_SUCCESS;
}

It produces: "4 8"

Constructors were added to prevent aggressive optimization by the compiler. Because the program does not create objects of these types, constructors don't have to be actually defined in a separate compilation module. The same is true for the const int

dmityugov
A: 

In reading previous posts i noticed that no one mentioned an "enum in a namespace" trick. If you like enums because you are working on an older compiler (I've had such experience on VxWorks/Tornado embedded programming platform), then listen up: you can avoid naming collisions by placing enum inside a namespace or (if namespaces aren't supported either) inside a class.

GregC