Why can't I initialize a non-stationary static member or static array in a class?

Why can't I initialize a non-const static member or static array in a class?

 class A { static const int a = 3; static int b = 3; static const int c[2] = { 1, 2 }; static int d[2] = { 1, 2 }; }; int main() { A a; return 0; } 

the compiler produces the following errors:

 g++ main.cpp main.cpp:4:17: error: ISO C++ forbids in-class initialization of non-const static member 'b' main.cpp:5:26: error: a brace-enclosed initializer is not allowed here before '{' token main.cpp:5:33: error: invalid in-class initialization of static data member of non-integral type 'const int [2]' main.cpp:6:20: error: a brace-enclosed initializer is not allowed here before '{' token main.cpp:6:27: error: invalid in-class initialization of static data member of non-integral type 'int [2]' 

I have two questions:

  • Why can't I initialize static data members in a class?
  • Why can't I initialize static arrays in a class, even in a const array?
+85
c ++ static const
Mar 11 2018-12-12T00:
source share
4 answers

Why can't I initialize static members in a class?

The C ++ standard allows you to initialize only static constant integral or enumerated types within a class. For this reason, a allowed to initialize, while others are not.

Reference:
C ++ 03 9.4.2 Static Data Elements
Β§ four

If the static data member is of type const const or const, its declaration in the class definition may indicate an initializer constant, which must be an integral constant expression (5.19). In this case, the term can appear in integral constant expressions. A member still needs to be defined in the namespace area, if used in the program, and the namespace area definition should not contain an initializer.

What are integral types?

C ++ 03 3.9.1 Basic Types
Β§7

The types are bool, char, wchar_t, and signed and unsigned integer types are called integral types. 43) A synonym for an integral type is an integer type.

Footnote:

43) Therefore, transfers (7.2) are not integer; however, enumerations can be translated into int, unsigned int, long or unsigned long, as specified in 4.5.

Workaround:

You can use the enum trick to initialize an array inside your class definition.

 class A { static const int a = 3; enum { arrsize = 2 }; static const int c[arrsize] = { 1, 2 }; }; 

Why does the standard not allow this?

Bjarne explains this aptly here :

A class is usually declared in the header file, and the header file is usually included in many translation units. However, to avoid complex linker rules, C ++ requires each object to have a unique definition. This rule will be violated if C ++ allows the definition of a class in a class, which should be stored in memory as objects.

Why are only static const integral types and enums allowed in-class initialization?

The answer is hidden in Bjarne’s quote, read it carefully,
"C ++ requires that every object has a unique definition. This rule would be violated if C ++ allowed the definition of a class of objects in a class that needed to be stored in memory as objects."

Note that static const integers can be considered as compile-time constants. The compiler knows that the integer value will not change at any time and, therefore, it can apply its own magic and apply optimizations, the compiler simply inserts such members of the class, that is, they are no longer stored in memory, since the need to save in memory is deleted, it gives such variables an exception to the rule mentioned by Bjarne.

It should be noted here that even if the integral values ​​of static const can have In-Class Initialization, the use of the address of such variables is unacceptable. You can accept the address of a static member if (and only if) has a definition outside the class. This further confirms the rationale above.

enums are allowed, since values ​​of an enumerated type can be used where ints are expected. see quote above




How does this change in C ++ 11?

C ++ 11 mitigates the limitation to a certain extent.

C ++ 11 9.4.2 Static Data Elements
Β§3

If the static data member is of type const literal, its declaration in the class definition may indicate a boolean or equal-initializer, in which each initializer clause, which is an assignment expression, is a constant expression. The static literal data member can be declared in the class definition using the constexpr specifier; if so, its declaration specifies a logical or equal-initializer in which each initializer clause, which is an assignment expression, is a constant expression, [Note. In both cases, the term can be displayed in constant expressions. -end note] A member must still be defined in the namespace scope if used in the program, and the namespace scope definition must not contain an initializer.

In addition, C ++ 11 will allow (Β§12.6.2.8) a non-static data member to be initialized where it is declared (in its class). This will mean very easy user semantics.

Please note that these functions are not yet implemented in the latest gcc 4.7, so you can still get compilation errors.

+115
Mar 11 2018-12-12T00:
source share
β€” -

This seems like a relic from the old days of simple linkers. You can use static variables in static methods as a workaround:

 // header.hxx #include <vector> class Class { public: static std::vector<int> & replacement_for_initialized_static_non_const_variable() { static std::vector<int> Static {42, 0, 1900, 1998}; return Static; } }; int compilation_unit_a(); 

and

 // compilation_unit_a.cxx #include "header.hxx" int compilation_unit_a() { return Class::replacement_for_initialized_static_non_const_variable()[1]++; } 

and

 // main.cxx #include "header.hxx" #include <iostream> int main() { std::cout << compilation_unit_a() << Class::replacement_for_initialized_static_non_const_variable()[1]++ << compilation_unit_a() << Class::replacement_for_initialized_static_non_const_variable()[1]++ << std::endl; } 

assembly:

 g++ -std=gnu++0x -save-temps=obj -c compilation_unit_a.cxx g++ -std=gnu++0x -o main main.cxx compilation_unit_a.o 

mileage:

 ./main 

The fact that this works (sequentially, even if the class definition is included in different compilation units) shows that the linker today (gcc 4.9.2) is actually smart enough.

Funny: prints 0123 on the hand and 3210 on x86.

+3
Jul 24 '15 at 10:26
source share

I think this is stopping you from mixing declarations and definitions. (Think about the problems that may arise if you include the file in several places.)

+2
Mar 11 2018-12-12T00:
source share
Static variables

belong to the class. Constructors initialize the ESPECIALY attributes for the instance.

-3
Mar 23 '15 at 19:16
source share



All Articles