Must I provide an explicit initializer for the definition of static members of integral type outside the class body, or can I safely omit that? Omitting the initializer and accessing the value seems to return a value of 0 every time, this implies that it is indeed value initialized and can be omitted. What does the standard say about this?
Static members of the class are entities with external linkage. The compiler expects you to define that entity in some translation unit. The whole purpose of this feature is to give you the opportunity to choose that translation unit. The compiler cannot choose it for you. It is, again, a part of your intent, something you have to tell the compiler.
In early C++ it was allowed to define the static data members inside the class which certainly violate the idea that class is only a blueprint and does not set memory aside. This has been dropped now.
Putting the definition of static member outside the class emphasize that memory is allocated only once for static data member (at compile time). Each object of that class doesn't have it own copy.
Starting from C++17 you can declare your static members as inline. This eliminates the need for a separate definition. By declaring them in that fashion you effectively tell the compiler that you don't care where this member is physically defined and, consequently, don't care about its initialization order.
Related
According to Static data members on the IBM C++ knowledge center:
The declaration of a static data member in the member list of a class is not a definition. You must define the static member outside of the class declaration, in namespace scope.
Why is that? What's the schematic behind that regarding the memory allocation?
It's a rule of the language, known as the One Definition Rule. Within a program, each static object (if it's used) must be defined once, and only once.
Class definitions typically go in header files, included in multiple translation units (i.e. from multiple source files). If the static object's declaration in the header were a definition, then you'd end up with multiple definitions, one in each unit that includes the header, which would break the rule. So instead, it's not a definition, and you must provide exactly one definition somewhere else.
In principle, the language could do what it does with inline functions, allowing multiple definitions to be consolidated into a single one. But it doesn't, so we're stuck with this rule.
It's not about the memory allocation piece at all. It's about having a single point of definition in a linked compilation unit. #Nick pointed this out as well.
From Bjarne's webite https://www.stroustrup.com/bs_faq2.html#in-class
A class is typically declared in a header file and a header file is
typically included into many translation units. However, to avoid
complicated linker rules, C++ requires that every object has a unique
definition. That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
As of C++17 you can now define static data members inside a class. See cppreference:
A static data member may be declared inline. An inline static data
member can be defined in the class definition and may specify an
initializer. It does not need an out-of-class definition:
struct X {
inline static int n = 1;
};
According to the definition of static data members, we can define static variables only for once (i.e in class only) and it is shared by every instance of the class. Also, static members can be accessed without any object.
As per OOPS guidelines compiler does not allocate memory to class instead of that it allocates memory to objects, but static members are independent of object, so to allocate memory to static variables, we define the static data members outside of the class, that's why once this variable is declared, it exists till the program executes. Generally static member functions are used to modify the static variables.
According to Static data members on the IBM C++ knowledge center:
The declaration of a static data member in the member list of a class is not a definition. You must define the static member outside of the class declaration, in namespace scope.
Why is that? What's the schematic behind that regarding the memory allocation?
It's a rule of the language, known as the One Definition Rule. Within a program, each static object (if it's used) must be defined once, and only once.
Class definitions typically go in header files, included in multiple translation units (i.e. from multiple source files). If the static object's declaration in the header were a definition, then you'd end up with multiple definitions, one in each unit that includes the header, which would break the rule. So instead, it's not a definition, and you must provide exactly one definition somewhere else.
In principle, the language could do what it does with inline functions, allowing multiple definitions to be consolidated into a single one. But it doesn't, so we're stuck with this rule.
It's not about the memory allocation piece at all. It's about having a single point of definition in a linked compilation unit. #Nick pointed this out as well.
From Bjarne's webite https://www.stroustrup.com/bs_faq2.html#in-class
A class is typically declared in a header file and a header file is
typically included into many translation units. However, to avoid
complicated linker rules, C++ requires that every object has a unique
definition. That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
As of C++17 you can now define static data members inside a class. See cppreference:
A static data member may be declared inline. An inline static data
member can be defined in the class definition and may specify an
initializer. It does not need an out-of-class definition:
struct X {
inline static int n = 1;
};
According to the definition of static data members, we can define static variables only for once (i.e in class only) and it is shared by every instance of the class. Also, static members can be accessed without any object.
As per OOPS guidelines compiler does not allocate memory to class instead of that it allocates memory to objects, but static members are independent of object, so to allocate memory to static variables, we define the static data members outside of the class, that's why once this variable is declared, it exists till the program executes. Generally static member functions are used to modify the static variables.
According to Static data members on the IBM C++ knowledge center:
The declaration of a static data member in the member list of a class is not a definition. You must define the static member outside of the class declaration, in namespace scope.
Why is that? What's the schematic behind that regarding the memory allocation?
It's a rule of the language, known as the One Definition Rule. Within a program, each static object (if it's used) must be defined once, and only once.
Class definitions typically go in header files, included in multiple translation units (i.e. from multiple source files). If the static object's declaration in the header were a definition, then you'd end up with multiple definitions, one in each unit that includes the header, which would break the rule. So instead, it's not a definition, and you must provide exactly one definition somewhere else.
In principle, the language could do what it does with inline functions, allowing multiple definitions to be consolidated into a single one. But it doesn't, so we're stuck with this rule.
It's not about the memory allocation piece at all. It's about having a single point of definition in a linked compilation unit. #Nick pointed this out as well.
From Bjarne's webite https://www.stroustrup.com/bs_faq2.html#in-class
A class is typically declared in a header file and a header file is
typically included into many translation units. However, to avoid
complicated linker rules, C++ requires that every object has a unique
definition. That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
As of C++17 you can now define static data members inside a class. See cppreference:
A static data member may be declared inline. An inline static data
member can be defined in the class definition and may specify an
initializer. It does not need an out-of-class definition:
struct X {
inline static int n = 1;
};
According to the definition of static data members, we can define static variables only for once (i.e in class only) and it is shared by every instance of the class. Also, static members can be accessed without any object.
As per OOPS guidelines compiler does not allocate memory to class instead of that it allocates memory to objects, but static members are independent of object, so to allocate memory to static variables, we define the static data members outside of the class, that's why once this variable is declared, it exists till the program executes. Generally static member functions are used to modify the static variables.
According to Static data members on the IBM C++ knowledge center:
The declaration of a static data member in the member list of a class is not a definition. You must define the static member outside of the class declaration, in namespace scope.
Why is that? What's the schematic behind that regarding the memory allocation?
It's a rule of the language, known as the One Definition Rule. Within a program, each static object (if it's used) must be defined once, and only once.
Class definitions typically go in header files, included in multiple translation units (i.e. from multiple source files). If the static object's declaration in the header were a definition, then you'd end up with multiple definitions, one in each unit that includes the header, which would break the rule. So instead, it's not a definition, and you must provide exactly one definition somewhere else.
In principle, the language could do what it does with inline functions, allowing multiple definitions to be consolidated into a single one. But it doesn't, so we're stuck with this rule.
It's not about the memory allocation piece at all. It's about having a single point of definition in a linked compilation unit. #Nick pointed this out as well.
From Bjarne's webite https://www.stroustrup.com/bs_faq2.html#in-class
A class is typically declared in a header file and a header file is
typically included into many translation units. However, to avoid
complicated linker rules, C++ requires that every object has a unique
definition. That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
As of C++17 you can now define static data members inside a class. See cppreference:
A static data member may be declared inline. An inline static data
member can be defined in the class definition and may specify an
initializer. It does not need an out-of-class definition:
struct X {
inline static int n = 1;
};
According to the definition of static data members, we can define static variables only for once (i.e in class only) and it is shared by every instance of the class. Also, static members can be accessed without any object.
As per OOPS guidelines compiler does not allocate memory to class instead of that it allocates memory to objects, but static members are independent of object, so to allocate memory to static variables, we define the static data members outside of the class, that's why once this variable is declared, it exists till the program executes. Generally static member functions are used to modify the static variables.
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.
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.
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.
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.