Defining Static Members in C++

How to initialize private static members in C++?

The class declaration should be in the header file (Or in the source file if not shared).

File: foo.h

class foo
{
private:
static int i;
};

But the initialization should be in source file.

File: foo.cpp

int foo::i = 0;

If the initialization is in the header file then each file that includes the header file will have a definition of the static member. Thus during the link phase you will get linker errors as the code to initialize the variable will be defined in multiple source files.
The initialisation of the static int i must be done outside of any function.

Note: Matt Curtis: points out that C++ allows the simplification of the above if the static member variable is of const integer type (bool, char, char8_t [since C++20], char16_t, char32_t, wchar_t, short, int, long, long long, or any implementation-defined extended integer types, including any signed, unsigned, and cv-qualified variants.). You can then declare and initialize the member variable directly inside the class declaration in the header file:

class foo
{
private:
static int const i = 42;
};

What does static mean in C?

  1. A static variable inside a function keeps its value between invocations.
  2. A static global variable or a function is "seen" only in the file it's declared in

(1) is the more foreign topic if you're a newbie, so here's an example:

#include <stdio.h>

void foo()
{
int a = 10;
static int sa = 10;

a += 5;
sa += 5;

printf("a = %d, sa = %d\n", a, sa);
}


int main()
{
int i;

for (i = 0; i < 10; ++i)
foo();
}

This prints:

a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60

This is useful for cases where a function needs to keep some state between invocations, and you don't want to use global variables. Beware, however, this feature should be used very sparingly - it makes your code not thread-safe and harder to understand.

(2) Is used widely as an "access control" feature. If you have a .c file implementing some functionality, it usually exposes only a few "public" functions to users. The rest of its functions should be made static, so that the user won't be able to access them. This is encapsulation, a good practice.

Quoting Wikipedia:

In the C programming language, static
is used with global variables and
functions to set their scope to the
containing file. In local variables,
static is used to store the variable
in the statically allocated memory
instead of the automatically allocated
memory. While the language does not
dictate the implementation of either
type of memory, statically allocated
memory is typically reserved in data
segment of the program at compile
time, while the automatically
allocated memory is normally
implemented as a transient call stack.

And to answer your second question, it's not like in C#.

In C++, however, static is also used to define class attributes (shared between all objects of the same class) and methods. In C there are no classes, so this feature is irrelevant.

Defining static members in C++

(1.) Why is it not allowed in C++ ?

From Bjarne Stroustrup's C++ Style and Technique FAQ:

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.

(2.) Why are const members allowed to
be initialized ?

[dirkgently said it better]

(3.) Does this mean static variables
in C++ are not initialized with 0 as
in C?

As far as I know, as long as you declare the static member var in a .cpp it will be zero-initialized if you don't specify otherwise:

// in some .cpp
int Test::j; // j = int();

How to declare and initialize a static member in a class?

One can definitely have class static members which are not CV-qualified (non const and not volatile). It is just that one should not initialize them (give them value) when one declare them inside the class, based on current ISO C++ regulations. In Comparison, it is OK to do so for non static data members(regardless of CV-qualification) Since C++11.

Because static data members do not belong to any object, with the right access they can be assigned (and if they are not constant, they can be manipulated) outside of the class(keeping in mind the right scope operator). Also regardless of public/private declaration and CV-qualification, static data members can be initialized outside their class.

So one way for initializing static data members, is to do so in the same block-scope/namespace where their classes(outer class in case of sub-classes) are situated, but not inside any class scope.

For example:

class Graph {
public:
class Node {
public:
static int maxNumberOfNeighbors;
.
.
.
};
.
.
.
};

int Graph::Node::maxNumberOfNeighbors = 4;
//also int Graph::Node::maxNumberOfNeighbors(4);


Good luck!

Why static members need to be initialized out of the class

What you call initialization is really a definition.

And the reason is that definitions can only be done once is a single translation unit.

If the static member variable were defined in the header file it could be defined multiple times breaking the one definition rule.

Or the compiler would not know which translation unit to put the definition in, since it doesn't know anything about other possible translation units.

Static class member variable and static variable in c++

The only reason is code cleanliness. You cannot restrict access to a global static variable like

static int globalValue=5;

it is (at least) visible in the source file you defined it.
With a class static, you can give a user of your class hints, how you wish to access it or be accessed. It is only visible within the class scope:

class myGlobalContainer
{
public:
static int myInt;
protected:
static float myFloat;
private:
static bool myBool;
};

the access of myInt is done by:

int x=myGlobalContainer::myInt;

the public modifier gives the user the hint that you see this value as part of the myGlobalContainer and wish him to use it. You do not polute the global namespace like you do with the globalValue.

The modifier protected and private shows that you do not wish that an "outsider" access those values.

protected and private static attributes are mostly used to share information between the instances of a class, for e.g. a instance counter:

class myGlobalContainer
{
public:
myGlobalContainer()
{
if(counter==0)
DoSomeSpecialGlobalInit();
counter++;
}
~myGlobalContainer()
{
counter--;
if(counter==0)
DoSomeSpecialGlobalUnInit();
}
private:
static int counter=0;
};

public static attributes are often seen with const. They mostly give a user a shortcut. For e.g.:

COLOR white=COLOR::WHITE;

instead of:

COLOR white=COLOR::FromAGBR(255,255,255,255);

Add least:
If you should use statics or not is a complete other discussion.

How to initialize a static const member in C++?

YES you can but only for int types.
If you want your static member to be any other type, you'll have to define it somewhere in a cpp file.

class A{
private:
static const int a = 4; // valid
static const std::string t ; // can't be initialized here
...
...
};


// in a cpp file where the static variable will exist
const std::string A::t = "this way it works";

Also, note that this rule have been removed in C++11, now (with a compiler providing the feature) you can initialize what you want directly in the class member declaration.

Static data member initialization in the class definition?

why (for what?) it is impossible to initialize the static variable inside the class?

It is not impossible to initialise static variables inside the class definition, if they are const.

But actually without std::size_t const s::len - this line it's compiles successfully too, so in what cases it shouldn't work?

It works because the variable was not odr-used. See [basic.def.odr]:

A variable x whose name appears as a potentially-evaluated expression e is odr-used by e unless

  • x is a reference ...
  • x is a variable of non-reference type that is usable in constant expressions and has no mutable subobjects, and e is an element of the set of potential results of an expression of non-volatile-qualified non-class type to which the lvalue-to-rvalue conversion ([conv.lval]) is applied, or ...

Besides, ODR violations are no diagnostic required. This is technically true for missing definitions. An optimisation might remove odr-uses so that they don't manifest as errors.

Try the following to odr-use the variable:

const int *ptr = &X::n;
  1. Why const static data members may be defined in the class definition?

No. Non-inline const static data members are not defined by the declaration in the class definition. There needs to be a definition (outside the class) if the variable is odr-used.


  1. Why static data members [...] may not be defined in the class definition (see my thoughts about template classes with static members and Stroustrup words about this (does he cheat us?))?

Stroustrup is correct about "complicated linker rules". Those were avoided when it was not possible to define static variables in headers.

Your point about templates makes sense. Those complicated linker rules were needed anyway to make templated static variables possible. And being able to define even non-templated static variables has advantages. These are probably the reasons why the committee chose to allow defining static members in class definition in C++17. See: inline static member definition.

What is the correct way to initialize static data members in C++ (98, 11 and 14)

The rules have always been as follows:

  • A const static data member (SDM) of integral or enumeration type can be initialised in class with a constant expression.

  • A constexpr SDM must be initialised in class with a constant expression.

    C++17 no longer requires an initializer when the default constructor initialises every member. Also, constexpr SDMs are implicitly inline variables, which makes their declaration a definition (external definitions are now deprecated).

  • Other kinds of SDMs can have an initializer at their definition (which is in class if that SDM is declared inline).

Nothing has substantially changed between C++03 and C++11+ for code that is valid in both languages.

Note that for SDMs that are not inline, the in-class declaration is not a definition—regardless of whether an initializer is provided—and they must be defined if they are odr-used.

As of C++17, we can make your SDM inline, which makes its in-class declaration a definition:

class BufferedOutput
{
static inline long bytecount = 50;
};

Why static variable needs to be explicitly defined?

From the beginning of time C++ language, just like C, was built on the principle of independent translation. Each translation unit is compiled by the compiler proper independently, without any knowledge of other translation units. The whole program only comes together later, at linking stage. Linking stage is the earliest stage at which the entire program is seen by linker (it is seen as collection of object files prepared by the compiler proper).

In order to support this principle of independent translation, each entity with external linkage has to be defined in one translation unit, and in only one translation unit. The user is responsible for distributing such entities between different translation units. It is considered a part of user intent, i.e. the user is supposed to decide which translation unit (and object file) will contain each definition.

The same applies to static members of the class. 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.

This is no longer as critical as it used to be a while ago, since the language is now designed to deal with (and eliminate) large amount of identical definitions (templates, inline functions, etc.), but the One Definition Rule is still rooted in the principle of independent translation.

In addition to the above, in C++ language the point at which you define your variable will determine the order of its initialization with regard to other variables defined in the same translation unit. This is also a part of user intent, i.e. something the compiler cannot decide without your help.


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 compiler that you don't care where this member is physically defined and, consequently, don't care about its initialization order.



Related Topics



Leave a reply



Submit