Why I can write this:
class VoiceManager
{
public:
static const int mMaxNumOfVoices = 16;
Voice mVoices[mMaxNumOfVoices];
private:
};
but I can't use this:
class VoiceManager
{
public:
const int mMaxNumOfVoices = 16;
Voice mVoices[mMaxNumOfVoices];
private:
};
It says: "a nonstatic member reference must be relative to a specific object"
But in both case, mMaxNumOfVoices is a const and will be init before mVoices init (compiler follow the declaration order, no?).
But it requires static. Why?
Array bounds must be known at compile-time. Though your initialisation is written there in the code, it can be overridden at runtime by a constructor. Hence your non-static member variable is not a compile-time constant.
The const keyword means read-only, not constant, is like a not-be-changed promise for a specific part of the program. If you have a pointer-to-const then other parts of the program may change the value while you're not looking.
But a static const is guaranteed that remains unchanged for the rest of the program. The storage for the object is allocated when the program begins and deallocated when the program ends. Only one instance of the object exists. All objects declared at namespace scope (including global namespace) have this storage duration.
Related
I saw this at work, and it is written by people before I joined. A static variable is used instead of static member of the class. As for now, I don't see a reason why static member of the class should not be used here. If I want to persuade people here to change it, is there any good excuse to convince them?
I tried to find the difference between static member and static variable, seems like people are leaning toward static member shall always be used unless there is a good reason, but not very real life cases were mentioned.
Current code:
class Foo {
public:
static Foo *get() {
static Foo _instance;
return &_instance;
}
// ...
};
How this function is being used:
int XXX_loadxxx(const char xxx, foo_handle *handle) {
// just get foo ptr and return
xxx::foo *ptr = xxx::foo::get();
int ret = ptr->init();
if (ret != 0) {
return -1;
}
*handle = ptr;
return 0;
}
Code in my mind how the class should be defined:
class Foo {
static Foo _instance;
public:
static Foo *get() {
return &_instance;
}
// ...
};
I'd really appreciate if someone can tell me whether it makes any different to change it to static member, and why.
The first solution is better for two reasons:
the static singleton is initialized the first time get() is called, which means you have a predictable behavior, which is not the case with static variables on different translation units
the variable is local so it's only visible from the getter of the singleton, which is usually what you want
I don't see why you would prefer to de-encapsulate it from the method.
Both samples cannot be compiled. What does the static Foo_instance mean? Did you mean static Foo instance?
Now back to your question: if you define the static variable inside of a function, it will be initialized only when you call the function for the first time. That has 2 consequences:
You will not spend resources if you never use this object;
If the constructor requires other resources to be allocated, you may need to control the time of creation. The time of creation of the static member is not defined.
The static member variable (as well as static variables in namespace scope) has a few disadvantages compared to a static local variable:
It must be defined in a single translation unit. This is not an option for libraries that desire to be "header only". This limitation no longer exists in C++17, which introduced inline variables.
The order of initialisation of static objects defined in different translation units is undefined. This often leads to undefined behaviour when static objects depend on other static objects, and may get initialised in the wrong order. This problem is called "Static Initialization Order Fiasco". The function local static (mostly1) solves this problem, since it is instead initialised on first use. As such, this idiom is called "Construct On First Use".
1 There is still a convoluted way of violating the ordering guarantees even with Construction On First Use: If there is static object A, whose constructor does not depend on static object B, but the destructor of A does depend on B, then B may still be destroyed first resulting in UB. This can be avoided by always calling the static getter of B in the constructor of A if any part of the A depends on B. In general, static objects should be avoided because of these problems.
P.S. Typically, you'd want to return a reference from the getter, so that the caller doesn't need to worry about getting null.
P.P.S. static Foo_instance; should probably be static Foo instance;
P.P.P.S. With the static member, the getter becomes mostly2 useless; the member could instead be made public.
2 It may still have some value if you intend to use inheritance, to extend the static object while maintaining compatibility with the original interface.
The local static varaible initialization is safe in a concurrent environment.
Another advantage is that it is initialized onlt in the case when the corresponding function is called. That is the variable is innitialized by a request.
From the C++ 17 Standard
4 Dynamic initialization of a block-scope variable with static storage
duration (6.6.4.1) or thread storage duration (6.6.4.2) is performed
the first time control passes through its declaration; such a variable
is considered initialized upon the completion of its initialization.
If the initialization exits by throwing an exception, the
initialization is not complete, so it will be tried again the next
time control enters the declaration. If control enters the
declaration concurrently while the variable is being initialized, the
concurrent execution shall wait for completion of the
initialization. If control re-enters the declaration recursively
while the variable is being initialized, the behavior is undefined
I am working with a class whose constructor declares and initializes a static const variable in the implementation. This is not a data member of the class. I understand the use of const in this context, but what is gained by using static?
I understand that the static const global constants are shared by all instances of the class. Does that also happen with the variable inside the constructor?
Also, why would this not be defined at the Global scope, like the other two? That's where I would normally define my constants.
Example Code:
#includes...
static const int GLOBAL_CONST1 = 100;
static const double GLOBAL_CONST2 = 1.0;
SomeClass::SomeClass()
:
theDataMember1 (),
theDataMember2 (),
...
{
static const double SOME_VAR = 0.01; // Why not declare this globally?
theDataMember1 = SomeIncludedClass(SOME_VAR);
}
Static Variable gets constructed only once no matter how many times the function is called.
So in case your defining constants inside a function and the function is called multiple times, then to reduce the cost of constructing this object every time the function is called you would make it a static variable (Mainly useful when its a constant, Else you may end up changing this value and it soon gets messed up).
For your second question, This is because you don't want others to be able to access the value of variable "SOME_VAR". Giving a global scope means any one can access it.
This link provides a good example about how local static is sometimes useful than global static variables.
When the constant is used only in one single function it can make sense to declare it only in the scope of the function it is used in. Why the static is used here does not really make sense to me, because it will be the same in all instances of the class anyway since it is a compile time constant.
But:
You can also initialize the constant from parameters computed at runtime. In that case the value of the constant will be defined by the first instance of the class:
class A {
public:
A(int param)
{
static const int MY_CONST = param;
cerr << "param: " << param << " const: " << MY_CONST << endl;
};
};
int main()
{
A a1(1);
A a2(2);
return 0;
}
output:
param: 1 const: 1
param: 2 const: 1
// Why not declare this globally?
By only seeing an abridged code fragment, we can only guess. It's typically good practice to put your variables in the narrowest scope possible. After all, everything could be global - we just choose to encapsulate things.
Perhaps the global constants are actually used in a lot of places, whereas the local constant is only used in that local function.
but what is gained by using static?
Probably just consistency. If you're just used to typing your constant values like:
static const T val = ddd;
everywhere, why change when you do it locally? There isn't an advantage or disadvantage of static for creating constant numbers.
static variables are literally static: they are allocated in same place as global variables. Plain local variables are allocated every time function is called on stack. If function is called n times recursively, there are n local variables. Static variable initialized only once. After it has been initialized, there is be only one instance of static variable. So static const local variable is used because of performance reasons.
Variables should have as narrow scope as possible to avoid unnecessary coupling. That's why this variable is local.
This looks like an attempt at premature optimization. Allegedly someone who created the code believed that by using static double variable they will save on creating the variable every time the function is entered.
However, since compilers are not morons, in practice it doesn't matter at all. Optimizing compilers will replace the variable with access to pre-allocated and initialized memory regardless, static or no static.
According to the OP's Code:
#includes...
static const int GLOBAL_CONST1 = 100;
static const double GLOBAL_CONST2 = 1.0;
SomeClass::SomeClass()
:
theDataMember1 (),
theDataMember2 (),
...
{
static const double SOME_VAR = 0.01; // Why not declare this globally?
theDataMember1 = SomeIncludedClass(SOME_VAR);
}
One has to take into consideration a few things:
Data Storage Unit - Storage Class Specifier
Data Storage Duration - Minimum Life Of Data
Scope Visibility - Where The Data Unit Is Visible.
Here is an excerpt:
Global objects and objects in a namespace scope, static data members of a class, and local static objects in functions reside static storage duration. An object with static storage duration resides in the same memory address throughout the program's execution. Every such object is constructed only once during the lifetime of the program. By default, static data is initialized to binary zeros. Static objects with a nontrivial constructor or an explicit dynamic initializer undergo a second initialization phase called dynamic initialization.
The scope of an object declared static in a function is restricted to that function. Objects with static storage duration appear in the following examples:
int num=0; //global variables have static storage
extern int x; //also global, defined in a separate translation unit
int func()
{
static int calls; //local static. initialized to 0 by default
x=calls;
return ++calls;
}
class C
{
private:
static bool b;
};
namespace NS
{
std::string str; //str has static storage
}
The extern Storage Class Specifier
The extern specifier can be applied only to the names of objects and to functions. The extern specifier cannot be used in the declaration of class members or function parameters. Identifiers declared extern have external linkage, meaning they are visible from all translation units of the same program.
A name declared in a namespace scope without a storage-class-specifier has external linkage unless it has internal linkage because of a previous declaration and provided it is not declared const. Objects declared const and not explicitly declared extern have internal linkage, meaning they are visible only from the translation unit in which they are declared.
Notice that the extern keyword is overloaded. It can also be used in explicit-instantiations of templates and in and linkage-specifications, but it is not a storage-class-specifier in such contexts.
The thread_local Storage Duration
The thread_local specifier indicates that the named object or reference has thread storage duration. thread_local shall be applied only to the names of objects or references of namespace scope and to the names of objects or references of block scope that also specify static as their storage class. The thread_local storage class is a new C++09 feature. It's discussed in detail here.
that can be found at this site: C++ Reference Guide | Static Storage Duration
The OP had stated and asked this:
I am working with a class whose constructor declares and initializes a static const variable in the implementation. This is not a data member of the class. I understand the use of const in this context, but what is gained by using static?
I understand that the static const global constants are shared by all instances of the class. Does that also happen with the variable inside the constructor?
Also, why would this not be defined at the Global scope, like the other two? That's where I would normally define my constants.
To answer his/her questions based on the excerpt above and from my own intuition:
their first question:
"What is gained by using static?" static data storage units have automatic initialization. They are created only once and reside in that same memory address or allocation unit.
their second question:
"Does that also happen with the variable inside the constructor?" Yes & No - Yes there is a single instance of this variable upon construction and initialization in the static storage memory unit, but no this is not visible to every instance of the class; it is only local to the Constructor of this class because of scope visibility.
their final question:
"Also, why would this not be defined at the Global scope, like the other two?" This particular variable depending on intention of use might only be used in the initialization of another object. One of the benefits of this maybe to not having to use a stack variable, and is only visible to this class' constructor. So when this constructor is called ctor this static const variable is created and initialize only once per construction and once this class object's constructor goes out of scope this static const variable is no longer visible by any other function or member of this class, or any other translation unit that is outside the visibility of this scope.
There is no definitive answer, however I tried to provide as much insight as I can in regards to the OPs questions, and tried to answer them to the best of my abilities. Some of the things that can vary are the intentions of the programmer and the context in which these memory allocations units are, declared, defined, initialized and then used.
Why must static data member initialization be outside the class?
class X
{
public:
int normalValue = 5; //NSDMI
static int i;
};
int X::i = 0;
Why is the static data member (here "i") only a declaration, not a definition?
It's important to distinguish the initializer which says what its initial value is, and the definition. This modified code is valid, with the initializer in the class definition:
class X
{
public:
int normalValue = 5;
static const int i = 0; // declaration, with initializer
};
const int X::i; // definition
i.e. What must be outside the class is a definition, not the initialization.
That's because a variable must have an address in memory (unless it's only used in limited situations, such as in compile-time constant expressions.)
A non-static member variable exists inside the object it is a member of, so its address depends on the address of the object that contains it. Every time you create a new X you also create a new X::normalValue variable. The non-static data member's lifetime begins with the class' constructor. NSDMI syntax doesn't have anything to do with the variable's address in memory, it just allows you to provide an initial value in one place, instead of repeating it in every constructor with an explicit constructor initializer list.
On the other hand, a static member variable is not contained within an instance of the class, it exists independently of any single instance and exists from the start of the program, at a fixed address. In order for a static member variable (or any other global object) to get a unique address the linker must see exactly one definition of the static variable, in exactly one object file, and assign it an address.
Because a static variable needs exactly one definition in exactly one object file, it doesn't make sense to allow that definition to be provided in the class, since class definitions typically exist in header files and are included in multiple object files. So although you can provide an initializer in the class, you still need to define the static data member somewhere.
You can also look at it like declaring an extern variable:
namespace X {
extern int i;
}
This declares the variable, but there must be a definition somewhere in the program:
int X::i = 0;
You need to supply a separate definition for a static data member (if its odr-used, as defined in C++11) simply because that definition shall reside somewhere - in one and only one translation unit. Static class data members are basically global objects (global variables) declared in class scope. The compiler wants you to choose a specific translation unit that will hold the actual "body" of each global object. It is you who has to decide which translation unit to place the actual object to.
"static" class member is like a globally allocated variable (it is not related to the single class instance), so it must reside in some object file (and to be declared in the ".cpp" file) as a symbol just like any global variable.
Simple class member (non-static) resides in the memory block allocated for the class instance.
The simple reason is because classes are usually declared in header files, which often are included in multiple cpp files. Static data members have external linkage and must be declared in exactly one translation unit which makes them unfit for being defined inside a class.
As juanchopanza points out the following is allowed:
struct A
{
const static int i = 1;
};
However, this is only a declaration not a definition. You still need to define it if you are going to use i's address somewhere.
For example:
f(int);
g(int&);
X<A::i> x; // Okay without definition for template arguments
char a[A::i]; // Okay without definition, just using value as constant expression
&A::i; // Need a definition because I'm taking the address
f(A::i); // Okay without definition for pass by value
g(A::i); // Need a definition with pass by reference
Bear in mind that is is possible to initialize the static data member at the point of declaration if it is of const integral type of const enumeration type:
From the C++03 standard, §9.4.2
If a static data member is of const integral or const enumeration type, its declaration in the class
definition can specify a constant-initializer which shall be an integral constant expression (5.19)
struct Foo {
static const int j = 42; // OK
};
When the compiler generate binary code from a unit (extreme simplification: a cpp file and all its included headers) it will emit a symbol for the static variable and eventually initialization code for that variable.
It is okay for a static variable symbol to be declared in multiple units, but it is not okay for it to be initialized multiple times.
So you must make sure that the initialization code is only emitted for a single unit.
This mean that the static variable must be defined in exactly one unit.
Static Data Member
#include<iostream.h>
#include<conio.h>
class static_var
{
static int count; //static member of class
public :
void incr_staticvar()
{
count++;
}
void outputc()
{
cout<<"Value of Static variable Count :- "<<count<<endl;
}
};
int static_var::count;
void main()
{
clrscr();
static_var obj1,obj2,obj3,obj4;
obj1.incr_staticvar();
obj2.incr_staticvar();
obj3.incr_staticvar();
obj4.incr_staticvar();
cout<<"\nAfter Increment of static variable by Four Different objects is :-\n";
obj1.outputc ( );
obj2.outputc ( );
obj3.outputc ( );
obj4.outputc ( );
getch();
}
Why must static data member initialization be outside the class?
class X
{
public:
int normalValue = 5; //NSDMI
static int i;
};
int X::i = 0;
Why is the static data member (here "i") only a declaration, not a definition?
It's important to distinguish the initializer which says what its initial value is, and the definition. This modified code is valid, with the initializer in the class definition:
class X
{
public:
int normalValue = 5;
static const int i = 0; // declaration, with initializer
};
const int X::i; // definition
i.e. What must be outside the class is a definition, not the initialization.
That's because a variable must have an address in memory (unless it's only used in limited situations, such as in compile-time constant expressions.)
A non-static member variable exists inside the object it is a member of, so its address depends on the address of the object that contains it. Every time you create a new X you also create a new X::normalValue variable. The non-static data member's lifetime begins with the class' constructor. NSDMI syntax doesn't have anything to do with the variable's address in memory, it just allows you to provide an initial value in one place, instead of repeating it in every constructor with an explicit constructor initializer list.
On the other hand, a static member variable is not contained within an instance of the class, it exists independently of any single instance and exists from the start of the program, at a fixed address. In order for a static member variable (or any other global object) to get a unique address the linker must see exactly one definition of the static variable, in exactly one object file, and assign it an address.
Because a static variable needs exactly one definition in exactly one object file, it doesn't make sense to allow that definition to be provided in the class, since class definitions typically exist in header files and are included in multiple object files. So although you can provide an initializer in the class, you still need to define the static data member somewhere.
You can also look at it like declaring an extern variable:
namespace X {
extern int i;
}
This declares the variable, but there must be a definition somewhere in the program:
int X::i = 0;
You need to supply a separate definition for a static data member (if its odr-used, as defined in C++11) simply because that definition shall reside somewhere - in one and only one translation unit. Static class data members are basically global objects (global variables) declared in class scope. The compiler wants you to choose a specific translation unit that will hold the actual "body" of each global object. It is you who has to decide which translation unit to place the actual object to.
"static" class member is like a globally allocated variable (it is not related to the single class instance), so it must reside in some object file (and to be declared in the ".cpp" file) as a symbol just like any global variable.
Simple class member (non-static) resides in the memory block allocated for the class instance.
The simple reason is because classes are usually declared in header files, which often are included in multiple cpp files. Static data members have external linkage and must be declared in exactly one translation unit which makes them unfit for being defined inside a class.
As juanchopanza points out the following is allowed:
struct A
{
const static int i = 1;
};
However, this is only a declaration not a definition. You still need to define it if you are going to use i's address somewhere.
For example:
f(int);
g(int&);
X<A::i> x; // Okay without definition for template arguments
char a[A::i]; // Okay without definition, just using value as constant expression
&A::i; // Need a definition because I'm taking the address
f(A::i); // Okay without definition for pass by value
g(A::i); // Need a definition with pass by reference
Bear in mind that is is possible to initialize the static data member at the point of declaration if it is of const integral type of const enumeration type:
From the C++03 standard, §9.4.2
If a static data member is of const integral or const enumeration type, its declaration in the class
definition can specify a constant-initializer which shall be an integral constant expression (5.19)
struct Foo {
static const int j = 42; // OK
};
When the compiler generate binary code from a unit (extreme simplification: a cpp file and all its included headers) it will emit a symbol for the static variable and eventually initialization code for that variable.
It is okay for a static variable symbol to be declared in multiple units, but it is not okay for it to be initialized multiple times.
So you must make sure that the initialization code is only emitted for a single unit.
This mean that the static variable must be defined in exactly one unit.
Static Data Member
#include<iostream.h>
#include<conio.h>
class static_var
{
static int count; //static member of class
public :
void incr_staticvar()
{
count++;
}
void outputc()
{
cout<<"Value of Static variable Count :- "<<count<<endl;
}
};
int static_var::count;
void main()
{
clrscr();
static_var obj1,obj2,obj3,obj4;
obj1.incr_staticvar();
obj2.incr_staticvar();
obj3.incr_staticvar();
obj4.incr_staticvar();
cout<<"\nAfter Increment of static variable by Four Different objects is :-\n";
obj1.outputc ( );
obj2.outputc ( );
obj3.outputc ( );
obj4.outputc ( );
getch();
}
When a const member variable is defined/declared in a function or globally, storage may or may not be assigned to the variable depending on the use of it. e.g. if we are using "extern" for providing the variable an external linkage, then compiler is bound to assign storage to the variable. Otherwise compiler will keep it in symbol table.
Now when a const member variable is declared in a class like this:
class myClass {
const int myInt = 100;
}
In this situation, where does the compiler keep it?
Another question related to this which instantly came to my mind, should we declare it as private or protected?
The meaning of const in this context is different. It doesn't mean that myClass::myInt is a compile time constant, it means it cannot change during the lifetime of a myClass object. You can still pick its value at runtime. Other than that, it is just like a non-const data member.
For example:
struct myClass {
myClass(int i) : myInt(i) {} // needed for brace initialization pre-C++14
const int myInt = 100;
};
int main()
{
int n;
cin >> n;
myClass c{n};
}
So the compiler doesn't have the same freedom to perform optimizations as with a compile time constant.
In this situation, where does the compiler keep it?
Wherever it keeps the myClass instance the member belongs to, just like with any data member.
Another question related to this which instantly came to my mind, should we declare it as private or protected?
That is a matter of opinion and has nothing to do with const data members.