Say I have a C++ function:
void foo(int x) {
static int bar = x;
}
If I call foo(3) then afterwards call foo(4), it is my understanding that the value of bar will still be 3. Why is this? I understand why the memory allocation part of the initialization is redundant. but why is the assignment also ignored?
It is not an "assignment". It is an initialization. And, per rules of C++ language, initialization of static objects is performed only once - when the control passes over the declaration for the very first time.
In your example, the control passes over the declaration of bar when x is 3. So, bar is initialized with 3. It will never be "reinitialized", i.e. calling foo(4) will not affect bar at all. If you want to change the value of bar after that, you have to modify bar directly.
Short answer: because the standard says so.
Long answer: that's not an assignment, but an initialisation, and it's ignored because the standard says so.
Consider some different static variables:
void foo(int x) {
static int bar = x;
static std::string s1 = "baz";
static std::string s2("baz");
static int i{2}; // C++11-style uniform initialization
}
Do you also think s1 should get "assigned" the value "baz" every time the function is called? What about s2? What about i?
None of those statements perform any assignment, they are all initializations, and they are only done once. Just because a statement includes the = character doesn't make it an assignment.
A reason why the language is defined to work that way is that it's common to use a local static variable to run a function once:
bool doInit()
{
// run some one-time-only initialization code
// ...
return true;
}
void func() {
static bool init = doInit();
// ...
}
If init got assigned a value again every time the function is called then doInit() would get called multiple times, and would fail its purpose of running one-time-only setup.
If you want to change the value every time it's called, that's easy ... just change it. But if you don't want it to keep changing then there would be no way to do that if the language worked the way you are asking about.
It would also be impossible to have static const local variable:
void func() {
static const bool init = doInit();
// ...
}
Oops, this would try to change the value of init every time it's called.
The memory location for bar is not valid until the first call to foo, which is when bar gets instantiated. bar gets initialized to x when it gets instantiated. Every call to foo afterward, bar is already instantiated and therefore already initialized.
this is initialization of static variable instead of assigning values to it. with that being said, the value of bar would always be 3 if u call foo(3) at the very first place.
Related
This question already has answers here:
Why does initialization of local static objects use hidden guard flags?
(2 answers)
Closed 4 years ago.
As in the title - how does program know, that foo is already initialized when function is called second time:
int getFoo()
{
static int foo = 30;
return foo;
}
int main()
{
getFoo();
getFoo();
}
I want to know, whether the program stores some additional information about which static variable was already initialized.
Edit:
I found an answer here:
Why does initialization of local static objects use hidden guard flags?
Like I guessed - most compilers store additional "guard variable".
Have a look at [stmt.dcl]/4:
Dynamic initialization of a block-scope variable with static storage duration or thread storage duration 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.94 If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.
You have to be careful here. Primitive statics are initialised at compile time (as long as the initialisation value is a compile-time contant, as Peter points out), so in your example, GetFoo just, in effect, returns a constant.
HOWEVER...
statics which initialise an object (or initialise a primitive by calling a function) perform said initialisation when the scope in which they are declared is entered for the first time.
Furthermore, as of C++ 11 this has to be done in a threadsafe way, which generates a lot of extra code (although not much runtime overhead, after the first time through) and that might be an issue on, say, a micro-controller where code size often matters.
Here's a concrete example:
#include <iostream>
struct X
{
X () { std::cout << "Initialising m\n"; m = 7; }
int m;
};
void init_x ()
{
static X x;
}
int main () {
std::cout << "main called\n";
init_x ();
std::cout << "init_x returned\n";
}
Output:
main called
Initialising m
init_x returned
Live demo: https://wandbox.org/permlink/NZApcYYGwK36vRD4
Generated code: https://godbolt.org/z/UUcL9s
The following is adapted from a code:
void func()
{
static MyClass a = init_func();
a_global_var = null;
}
Does C++ compiler guarantees that the first assignment is before the 2nd?
Yes. But I shudder to think why you need to rely on this.
The first time the function is called, a is initialized with whatever is returned from init_func before a_global_var is later set to "null"
Note that as a is static, this only happens the first time the function is called. All subsequent times, a_global_var is set to null without any change to a by this function.
The first line is not an "assignment". It is an initialization. Since it is an initialization of a static object declared in block scope, it will be performed only once, when the control passes over it for the very first time, i.e. when you call your function for the first time.
The second line is indeed an assignment. It will be executed every time the control passes over it, i.e. every time you call your function.
This means that your question only makes sense for the first time this function is called. In that case the initialization is guaranteed to precede the assignment. In all subsequent calls the question will not apply at all, since the initialization will not be performed anymore.
"Does C++ compiler guarantees that the first assignment is before the 2nd?"
Yes, it's guaranteed.
Anyway you should consider to handle this in a singleton (if you really need to have it globally accessible):
class MyClass {
public:
static MyClass& instance() { // <<< replaces func()
static MyClass a;
return a;
}
void* global_var() { return a_global_var; }
private:
MyClass() : a_global_var(nullptr) { // <<< replaces init_func()
}
void* a_global_var;
};
Is modify const in constructor C++ standard? I was modifying my struct removing fixed-values(default member initializer) to set it later, at constructor-time but I forget to remove const keyword and noticied it later. To my surprise I didn't get a compile-error, it just worked fine but for test case 2 it give a compiler. How are they different?
test case 1:
struct A
{
const int x = 2;
A()
: x(3)
{
}
};
test case 2:
struct A
{
const int x = 2;
A()
{
x = 3; // compile error! error: read-only variable is not assignable
}
};
In the first example you are initializing the constant variable, in the second you are assigning a value to it, after the variable is default constructed. These are different operations and assignment is not possible for constants after their initialization.
This syntax was added in C++11:
struct A
{
const int x = 2;
In this case the 2 is like a "default" value to be used for initialization of x. If you initialize x in your constructor's initialization list, then that is the value used. However if you did not do so, then 2 is used.
This was added to C++11 to avoid the tedium of having to repeat things in the initialization lists if you had multiple constructors.
The thing is that the object must be fully initialized before the body of your constructor can proceed to start playing with it. This means that there must be reserved enough space in memory to which the instance of new object will be placed.
If you declare data member (int x) to be const, you prohibit yourself from ever changing it's value, once it is created, this means that the value must be set during it's creation.
In example 1 you first create the int x and set it to value 3 (which will reside in memory reserved for your object) and only after that the body of your constructor executes.
In example 2 you create new object (with some value for your int x) and than you try to modify it in your constructor, which is prohibited by the const keyword.
probably this might be a very basic question, but still wanna understand some basic concepts...
why do we define a variable as a const ? - to keep the value of that specific variable constant through out the program.
but, when i come across initialization list for constructors, that allows to assign value to the const variable during object construction( i tried the below program for ex.), i'm confused with the basic concept of const keyword itself. can someone clarify this?
what is the purpose of const variable in the following program, if it is allowed to change during object construction? do we have any real time scenarios for these kinda behavior? if so, can you please give some scenarios?
#include<iostream>
using namespace std;
class Test {
const int t;
public:
Test(int t):t(t) {} //Initializer list must be used
int getT() { return t; }
};
int main() {
Test t1(10);
cout<<t1.getT();
return 0;
}
Basically when data members are declared constant they have to have some value before the object is constructed Hence we use member initializer so that before the object is constructed the data member has some value.
in this program till the end the data member will have the same value
for real scenario:
For example you have to make a payroll program in which each employee has a first name and last name so you wouldn't want functions to accidentally modify their names so hence to prevent this you can keep them constant.
why do we define a variable as a const ?
A variable is declared const to indicate that it will not be changed.
but, when i come across initialization list for constructors, that allows to assign value to the const variable during object construction( i tried the below program for ex.), i'm confused with the basic concept of const keyword itself. can someone clarify this?
Is it not assignment but construction if it would be of not simple type but of MyClass, there constructor of MyClass would be used, not operator=
It does not change during the object-construction, because it has no (defined) value.
When you supply a const-member in a class, then this is a part of the object's identity and this particular value will stay the same through the object's life.
When declaring a member const you promise the compiler that you won't attempt to change the value of this member.
From MSDN
The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.
// constant_values1.cpp
int main() {
const int i = 5;
i = 10; // C3892
i++; // C2105
}
I want to know why constant data member of a class need to be initialized at the constructor and why not somewhere else? What is the impact of doing so and not doing so?
I also see that only static constant integral data can be initialized inside the class other than that non of the data members can be initialized inside the class.
for eg:- Suppose below is my class declaration
class A{
int a; // This we can initialize at the constructor or we can set this member by calling "vSet" member function
const int b;
static const int c = 10; //This works fine
public:
A();
~A();
void vSet(int a);
int iAdd();
void vDisplay();
};
And the constructor is defined as mentioned below:-
Edited Section: As previous constructor definition example was wrong
A::A():a(1),b(9){}
Please correct me if I am wrong.
Thanks in advance.
A::A(){
a = 1;
b = 9; // Why we need to initialize this only at the constructor.
}
Is not initialization but it is Assignment.
a and b are already constructed and you assign them values in this case. The const qualifier demands that the variable not be changed after its initialization, allowing this assignment would break that contract.
This is Initialization using Member Initialization list.
A::A():a(1),b(9)
{}
You might want to have a look at this answer of mine to know the difference:
What is the difference between Initializing and Assignment inside constructor?
As for another question, regarding only static constant integral data can be initialized inside the class, please read this answer of mine which explains in greater detail:
Why I can't initialize non-const static member or static array in class?
What you're doing is not initialization. It is assignment, so b=9 will NOT even compile, because b is a const, so cannot be assigned any value to it. It should be initialized, and to do that, use member-initialization list as:
A::A() : a(1), b(9)
{ // ^^^^^^^^^^^^ this is called member-initialization list
}
In C++11, you can use in-place initialization as:
class A{
int a = 1; //C++11 only
const int b = 9; //C++11 only
static const int c = 10; //This works fine (both in C++03 and C++11)
//...
};
Because it is constant, it's value cannot be changed. Initializing anywhere else other than the constructor would mean a default initialization, followed by an assignment, which is not permitted for a constant. It would be the equivalent of doing this:
const int i; // OK
i = 42; // Error!
Note that in C++11 it is perfectly OK to do this:
struct Foo {
const int i=42;
const double x = 3.1416;
};
But this follows the same rules, i.e there is no assignment.
A const data is a data that can never be changed. It is initialized once, and then keeps the same value forever.
Because of that, you can't just assign a value to it anywhere.
The constructor, however, is where initialization goes. So here, there is an exception, and you are able to assign a value to your const data. You can do this the classical way, or as many said, as initialization list.
Now, why you can't do this in the class definition (unlike, say, Java) when the variable is not static is another problem, that I know no answer to.
When the body of your constructor is entered, all members and sub-objects are already initialized. The only thing the constructor body can do is to change them – and that is, obviously, not allowed for const members.
You can, however, use an initializer list.
You can't initialize const members outside of a constructor because, well, they're const. By definition, you can't modify them after they've been initialized, and after the object has been constructed, anything that tries to set the value is a modification.
const values are meant to be rvalues, so they cannot appear on the right part of an expression due its constness.
so, when you use this expression on the constructor's body
A::A()
{
a = 1;
b = 9; // Why we need to initialize this only at the constructor.
}
You're using the const value as a lvalue, just as Als mentioned before. The fact is that you're trying to assing a new value to a variable that isn't allowed to change it's value afther it's lifetime had begun.
The correct way to assign values to a constant data member is in the ctor initializer list, that is, BEFORE the lifetime of the member value begins (as mentioned by Nawaz):
A::A() :
a(1),
b(9)
{
}
Finally, on the C++11 standard you're allowed to initialize all data members where it was declared, just like the static const ones.