tags:

views:

140

answers:

4

If I have a class that contains only compile-time constants, for example,

class A {
    static const int x = 1;
    static const int y = 2;
    static const int z = 3;
};

I believe it's the case that, so long as the address of the constants is not taken, they can (will?) be replaced at compile time where they are used and will not take up any space in the executable (as constants that is, obviously the numbers themselves are going to have to show up). If this is the case can/will the class also be optimized out? And, will this change if something inherits from class A, but still only uses the constants themselves and does not take their addresses?

Oh, and assuming, in the non-inheritance version, that the class is not actually used itself anywhere apart from as a means to access the constants.

Thanks.

+6  A: 

It doesn't matter whether those variables are const; they are static, so they won't affect the size of the class anyway.

sizeof(A) cannot be zero, so if you create an instance of A it has to be at least one byte in size. However, having A as a base class does not necessarily increase the size of a derived class because "base class sub-objects may have zero size" (C++03 §1.8/5).

James McNellis
AKA: "Empty Base Optimization", abbreviated as EBO, which may be used as a justification for using private inheritance instead of composition.
Matthieu M.
As in my comment to Suma's response. These classes are being created from templates to provide some compile time constants. I assumed the same rules apply but wonder now if this is the case. (And as with Suma, sorry for taking so long to get back to you).
tjm
+1  A: 

I believe that every type must have a sizeof of at least 1 (partly to ensure instance of that type get different addresses in an array for example).

Section 5.3.3 of the C++0x draft standard is where this is dictated:

When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array. The size of a most derived class shall be greater than zero.

They shouldn't affect the size of an instance (since they're static) but they will probably need to be stored in the executable somewhere since you need to be able to use the address-of operator on them. Whether they can be optimised out of existence depends entirely on the compiler and whether it can tell they're not being de-referenced. Enumerations are probably a better tool to use in this particular case.

However, three integers in an application is unlikely to cause a problem.

paxdiablo
+1. *need to be stored somewhere*... Static member constants must be defined in one translation unit for the program to be well defined if that constant is used anywhere in the program even when the static constant member is a compile time constant (9.4.2/4). *Somewhere* is the translation unit where they are defined.
David Rodríguez - dribeas
"must be defined in one translation unit for the program to be well defined". Why? If all places where the constant is use use it as a compile time constant (`literal`), and an address is not taken, they are in fact unused and I doubt there is any rule preventing the compiler to optimize them out.
Suma
+1  A: 

It's been given a size just because even object of such a class need to have a size. (For starters, if two such objects were members of another object, would they have distinct addresses if you form member pointers to them?) When this class is used as a base class, it will benefit from the empty base class optimization and be reduced to size 0. In fact, this

#include <iostream>

struct A {};
struct B { char x; };
struct C : public A, public B {};

int main()
{
    std::cout << sizeof(A) << '\n';
    std::cout << sizeof(B) << '\n';
    std::cout << sizeof(C) << '\n';
    return 0;
}

prints

1
1
1

for me, so A doesn't contribute anything to the size of C, which seems to support my interpretation that A's size of 1 is artificial.

sbi
I do not think new A for a zero sized object would be a problem. The same reasoning was behing a rule which required C malloc to return unique pointer for zero sized allocations. In practice this was achieved by always allocating at least a byte.There is a similar rule in C++ which requires class members to have a distinct member pointer to them - I think this the main reason why zero sized objects are not allowed.
Suma
@Suma: You might be right about that. I'll change my answer.
sbi
+2  A: 

Space used

No, the static const int member will will not have any space allocated for them, as they are evaluated as compile time constants.

As for size of the class object (i.e. sizeof(A)), this is not relevant unless you are creating instances of the class A - which you explicitly said you are not.

Use namespace instead?

That said, perhaps you could use namespace instead to make your intention a bit clearer? Unless you are using it for something like template traits, it seems you are abusing class to do the job namespaces are intended for.

Suma
+1 for the namespace - my thought exactly
Space_C0wb0y
namespaces cannot be used a template parameters. Whether this apply or not here being, of course, unknown to me :)
Matthieu M.
Exactly. That is probably why using class for template traits is an accepted practice, even when using namespace might be often more logical there.
Suma
Sorry that it took me so long to get back to this, I'm guessing its well forgotten about now, but just in case, my problem is exactly that these are classes built from templates. I've got a lot of classes being built via recursive templates to calculate just a few compile-time values and I'm wondering if the unused classes will still be taking up space although they are not really used. I should have made this clear in the question but I thought the same rules would apply, template or not, I may be wrong. I'll edit the question if this gets any feedback, if not I won't go bumping it back up.
tjm
Yes, the same rules apply. I have tried to answer in the first part - const static int members will take no space at all, and unless you are creating instances of the class, the size of the class does not matter.
Suma