Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Definition of a class's private integral constant: in the header or in the cpp file?

Tags:

c++

Subject has been addressed mostly here (Where to declare/define class scope constants in C++?) and in particular here.

What I would like to fully understand, in case of integral constants, is there any difference between:

//In the header
class A {
private:
static const int member = 0; //Declaration and definition
};

And:

//In the header
class A {
private:
static const int member; //Only declaration
};

//In the cpp
const int A::member = 0; //Definition

(I understand that the second might have the advantage that if I change the value of the constant, I have to recompile only one file)

Side questions:
What happens for example with an inline method defined in the header that access member? Will it simply be not inlined? What would happens if, going to one extreme, all methods were defined in the header file as inline methods and all constants were defined in the cpp file?

Edit:

My apologizes: I thought it was not necessary, but I missed the fact that the member is static. My question stays, but now the code is legal.

like image 908
Antonio Avatar asked Aug 09 '13 06:08

Antonio


3 Answers

If, as it was before the question was changed to make it static, it's a non-static member, then it can only be initialised in the constructor's initialiser list or (since 2011) in the member's declaration. Your second example was ill-formed.

If it's static, then you need a definition if it's odr-used: roughly speaking, if you do anything that requires its address rather than just its value. If you only use the value, then the first example is fine. But note that the comment is wrong - it's just a declaration, not a definition.

If you do need a definition, then it's up to you whether you specify the value in the declaration or the definition. Specifying it in the declaration allows better scope for optimisation, since the value is always available when the variable is used. Specifying it in the definition gives better encapsulation, only requiring one translation unit to be recompiled if it changes.

What happens for example with an inline method defined in the header that access member? Will it simply be not inlined?

There's no reason why accessing a data object defined in another translation unit should prevent a function from being inlined.

like image 103
Mike Seymour Avatar answered Nov 01 '22 14:11

Mike Seymour


There are two points of view to take into account, namely visibility and addressing.

Note that the two are orthogonal, for you can actually declare the variable as initialized and still define it in a translation unit so it has an effective address in memory.

Visibility

Visibility affects the usage of the variable, and has some technical impacts.

For usage in template code as a non-type template parameter, the value must be visible at the point of use. Also, in C++11, this might be necessary for constexpr usage. Otherwise, it is not necessary that the value be visible.

Technically a visible value can trigger optimizations from the compiler. For example if (A::member) is trivially false so the test can be elided. This is generally referred to as Constant Propagation. While this may seem a good thing, at first glance, there is a profound impact though: all clients of the header file potentially depends on this value, and thus any change to this value means they should be recompiled. If you deliver this header as part of a shared library, this means that changing this value breaks the ABI.

Addressing

The rule here is quite simple: if the variable can be addressed (either passed by pointer or reference), then it needs to reside somewhere in memory. This requires a definition in one translation unit.

like image 39
Matthieu M. Avatar answered Nov 01 '22 12:11

Matthieu M.


This is the question of data hiding. Whether you want to unveil internal class fields or not. If you are shipping a classes library and want to hide the implementation details then it is better to show in the interface as few entities as possible, then even a declaration of the private field member is too much.

I would just declare this value as a static variable inside a .cpp file.

like image 2
Sergey K. Avatar answered Nov 01 '22 14:11

Sergey K.