Const variable in C++ function body - c++

I believe I have it understod but I just want confirmation. If I have two functions,
function A()
{
const Vector3D vectorA(1.0f);
...
}
function B(float var)
{
const Vector3D vectorB(1.0f + var);
...
}
In the case of function A(), will vectorA only be constructed once in the program, no matter how many A() calls? I believe the compiler implicitly declares it static yes?
But in the case of B(), vectorB needs to be reconstructed each function call?

Both functions will create the variables every time they are called. There is no implicit static. Some compilers may choose to optimize but it is not part of the language specification.

The answer is no, however you are not that far off-track.
static is a very much overloaded keyword:
a static method is one that is not called on an instance of a class
a static attribute is one that exists only once for all instances of a class
a static function has internal linkage
a static variable, at namespace scope, has internal linkage
a static variable, at function scope, is also called local static; it is built the first time the execution flow pass through its definition and its state is then preserved between calls to the function it belongs to
Of all these uses, a single one can be (in effect) implicit: a const or constexpr variable at namespace scope has internal linkage (as if it were static) unless another storage qualifier is used (such as extern).
ยง3.5 Program and linkage [basic.link]
3/ A name having namespace scope (3.3.6) has internal linkage if it is the name of
a variable, function or function template that is explicitly declared static; or,
a variable that is explicitly declared const or constexpr and neither explicitly declared extern nor previously declared to have external linkage; or
a data member of an anonymous union.
Do note that const or constexpr thus never imply static, but in the specific case highlighted in the second bullet point for variables declared at namespace scope have the same effect on linkage.

No in both the cases the objects will be created upon every call.
Why should the compiler provide staticness implicitly in the first case ?

In the case of function A(), will vectorA only be constructed once in the program, no matter how many A() calls?
No. If you want only one construction of vectorA, you need to declare it as static:
const static Vector3D vectorA(1.0f);
I believe the compiler implicitly declares it static yes?
Don't assume that.

Related

Static variable vs static member

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

In C++, what is the benefit of defining a Static Const variable within a member function?

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 is it not allowed to put the `static` keyword for class member definitions in namespace scope?

struct A
{
static void f();
};
static void A::f() {} //illegal
Why's this not allowed? Am asking this because the rule seems inconsistent with other keywords.
You must put constexpr on both.
You can put inline on both, but you can also omit one of them. This is useful that you can omit inline in class definition, which is not important information of the interface.
But the rules for static on class members doesn't really make sense. Shouldn't it be consistent with constexpr?
I know static means internal linkage for namespace-scope functions, and this partly explains the current shape. But isn't distinguishing between free functions and class member functions having no ambiguity in namespace scope? For example, if you write static void A::f() {} it's unambiguous that you're defining a member function of A, if A is a class name.
The static in class have other meaning the static in a global or namespace.
when you declared symbol as static in the class, you don't want it to be a global static.
1. static member
In the class it is mean the symbol is class related not object related, means for member variable, there is only one instance for all the objects, and for function, it doesn't have access to non static members, which are object oriented. .
2. static global
In global scope, the static indicate the object or function is local only, and can't be exported (like using extern) to other files. in addition it let you use same name in other file for other variable. so if it located in header file, any file including the header, will have different instance of the symbol.
Therefore if you were allowed to use it in the global scope for a member, then there was an ambiguity.

Do the static (class) variables necessarily have to be const? [duplicate]

I understand that only data members which are static, const and int/enum (pre c++11) can be initialized inside the class declaration. "All other static data members must be defined at global namespace scope (i.e. outside the body of the class definition) and can be only initialized in those definitions".
Why can't other static data members be initialized in the class definition? Was there a specific reason this was forbidden?
If the data members are specific to the class, why are they declared at the global namespace scope and not some scope relevant to their class?
Why can't other static data members be initialized in the class definition? Was there a specific reason this was forbidden?
Most likely because C++ has separate translation units. The compiler needs to pick an object file where the initialization logic for those symbols will be placed. Forcing this to be in a specific source file makes that decision easy for the compiler.
If the data members are specific to the class, why are they declared at the global namespace scope and not some scope relevant to their class?
Because that's just how C++ does class members. This is no different than other class members like member functions:
Header file:
namespace example {
// Class declared in header
struct some_class
{
// Member variable
static float example;
// Member function
void DoStuff() const;
};
}
Source file:
namespace example {
// Implement member variable
float some_class::example = 3.14159;
// Implement member function
void some_class::DoStuff() const
{
//....
}
}
There's a specific exception to allow static const integral members to be initialized in the header because it allows the compiler to treat them as compile-time constants. That is, you can use them to define sizes of arrays or other similar bits in the class definition.
Why can't other static data members be initialized in the class definition? Was there a specific reason this was forbidden?
In general, all static objects require a definition, in one single translation unit, so that they have a well-defined address. As a special exception, static, constant, non-volatile class members don't need a definition if their address is not required, and they have a simple enough type that their value can be replaced by a compile-time constant.
Historically, "simple enough" was defined as an integral or enumeration type; C++11 extends that to include any literal type with a constexpr specifier.
If the data members are specific to the class, why are they declared at the global namespace scope and not some scope relevant to their class?
They are not declared at the global namespace scope. They are declared and scoped within the class.
If you mean, why are they defined outside the class definition, that's because there must be only one definition of the static member in the whole program; but the class must be defined in each translation unit that uses it.
Why can't other static data members be initialized in the class
definition? Was there a specific reason this was forbidden?
A static data member is in many respects (and especially from the point of view of a compiler) similar to a namespace-scope data object with external linkage.
The declaration of a static data member is just a declaration, not a definition. It is similar to an extern declaration of a global object and must be included into any translation unit where the object may be used.
The definition must appear in exactly one translation unit and this is where the initializer expression belongs. Unless an expression fulfills the strict criteria of a constant expression, its value may well depend upon the time and context it is called. Having such an initializer expression occur in multiple translation units would make the execution context and time of the initialization and finally the initial value ambiguous.
A class-scoped compile-time constant was deemed sufficiently valuable to make an exception for certain kinds of constant static members (which then could be used to initialize enums or specify array dimensions, etc). With constant expressions it is at least more difficult to accidentally incur different initializer values in different translation units. This concept was extended in C++11 with constexpr members.
If the data members are specific to the class, why are they declared
at the global namespace scope and not some scope relevant to their
class?
The declaration is within the class scope. The non-definition declaration is literally within the class definition and the definition appears at namespace scope, just like any other out-of-class definition of a class member. The member name is qualified by the class name, so it is clearly denoted as a member of the class and the initializer expression is actually considered to be within the scope of the class (at least in C++11; I have no C++98/03 standard available here).
You have to look at it the other way around. Basically, static data members must be defined and initialized outside the class definition, in a source file. There's an exception for static const int because it avoids various ugly workarounds for defining the size of a member array.
They would be re-initialized every time the class was instantiated. Every time you create a new object of type Foo, the static variables for all Foos would be reset to their initial value, which is probably not what you want. Therefore, if you want to use static variables with your object, they either a) can't change their value, meaning that reinitializing them to the same value is safe, or b) can only be changed outside the context of an initializer function.

Why do non-const, non-int/enum static data members have to be initialized outside the definition?

I understand that only data members which are static, const and int/enum (pre c++11) can be initialized inside the class declaration. "All other static data members must be defined at global namespace scope (i.e. outside the body of the class definition) and can be only initialized in those definitions".
Why can't other static data members be initialized in the class definition? Was there a specific reason this was forbidden?
If the data members are specific to the class, why are they declared at the global namespace scope and not some scope relevant to their class?
Why can't other static data members be initialized in the class definition? Was there a specific reason this was forbidden?
Most likely because C++ has separate translation units. The compiler needs to pick an object file where the initialization logic for those symbols will be placed. Forcing this to be in a specific source file makes that decision easy for the compiler.
If the data members are specific to the class, why are they declared at the global namespace scope and not some scope relevant to their class?
Because that's just how C++ does class members. This is no different than other class members like member functions:
Header file:
namespace example {
// Class declared in header
struct some_class
{
// Member variable
static float example;
// Member function
void DoStuff() const;
};
}
Source file:
namespace example {
// Implement member variable
float some_class::example = 3.14159;
// Implement member function
void some_class::DoStuff() const
{
//....
}
}
There's a specific exception to allow static const integral members to be initialized in the header because it allows the compiler to treat them as compile-time constants. That is, you can use them to define sizes of arrays or other similar bits in the class definition.
Why can't other static data members be initialized in the class definition? Was there a specific reason this was forbidden?
In general, all static objects require a definition, in one single translation unit, so that they have a well-defined address. As a special exception, static, constant, non-volatile class members don't need a definition if their address is not required, and they have a simple enough type that their value can be replaced by a compile-time constant.
Historically, "simple enough" was defined as an integral or enumeration type; C++11 extends that to include any literal type with a constexpr specifier.
If the data members are specific to the class, why are they declared at the global namespace scope and not some scope relevant to their class?
They are not declared at the global namespace scope. They are declared and scoped within the class.
If you mean, why are they defined outside the class definition, that's because there must be only one definition of the static member in the whole program; but the class must be defined in each translation unit that uses it.
Why can't other static data members be initialized in the class
definition? Was there a specific reason this was forbidden?
A static data member is in many respects (and especially from the point of view of a compiler) similar to a namespace-scope data object with external linkage.
The declaration of a static data member is just a declaration, not a definition. It is similar to an extern declaration of a global object and must be included into any translation unit where the object may be used.
The definition must appear in exactly one translation unit and this is where the initializer expression belongs. Unless an expression fulfills the strict criteria of a constant expression, its value may well depend upon the time and context it is called. Having such an initializer expression occur in multiple translation units would make the execution context and time of the initialization and finally the initial value ambiguous.
A class-scoped compile-time constant was deemed sufficiently valuable to make an exception for certain kinds of constant static members (which then could be used to initialize enums or specify array dimensions, etc). With constant expressions it is at least more difficult to accidentally incur different initializer values in different translation units. This concept was extended in C++11 with constexpr members.
If the data members are specific to the class, why are they declared
at the global namespace scope and not some scope relevant to their
class?
The declaration is within the class scope. The non-definition declaration is literally within the class definition and the definition appears at namespace scope, just like any other out-of-class definition of a class member. The member name is qualified by the class name, so it is clearly denoted as a member of the class and the initializer expression is actually considered to be within the scope of the class (at least in C++11; I have no C++98/03 standard available here).
You have to look at it the other way around. Basically, static data members must be defined and initialized outside the class definition, in a source file. There's an exception for static const int because it avoids various ugly workarounds for defining the size of a member array.
They would be re-initialized every time the class was instantiated. Every time you create a new object of type Foo, the static variables for all Foos would be reset to their initial value, which is probably not what you want. Therefore, if you want to use static variables with your object, they either a) can't change their value, meaning that reinitializing them to the same value is safe, or b) can only be changed outside the context of an initializer function.