I know that there are big problems with static initialization order in c++, basically there's no guarantees in it across translation units, however in the same translation unit there should be the guarantee that static objects are initialised in order that they appear. So why is this happening?
#include <iostream>
struct Foo {};
class SequentialTypeIDDispenser
{
private:
static inline int count = 0;
public:
static int init() { std::cout << "initialising static member\n"; return count++; }
template <typename type>
static inline int ID = init();
};
class Horse
{public:
static char init()
{
// Doesn't work, prints 0 all three times
std::cout << SequentialTypeIDDispenser::template ID<char> << "\n";
std::cout << SequentialTypeIDDispenser::template ID<double> << "\n";
std::cout << SequentialTypeIDDispenser::template ID<float> << "\n";
return 0;
}
static inline char member = init();
// Why is this being initialised before the static
// members of the above class?
};
int main()
{
// Now it works
std::cout << SequentialTypeIDDispenser::template ID<char> << "\n";
std::cout << SequentialTypeIDDispenser::template ID<double> << "\n";
std::cout << SequentialTypeIDDispenser::template ID<float> << "\n";
Horse horse;
}
The printed output is:
0
0
0
initialising static member
initialising static member
initialising static member
0
1
2
So we have a case where a static class member is being initialised before a static class member above it. Why is this happening?
Also, there is the other issue I don't understand, why if the program didn't get around to initialising the IDs yet, why is it printing 0? Is this just as undefined accident?
Your variables are dynamically initialized, with unordered initialization:
Unordered dynamic initialization, which applies only to (static/thread-local) class template static data members ... that aren't explicitly specialized. Initialization of such static variables is indeterminately sequenced with respect to all other dynamic initialization ...
[Emphasis mine]
Initialization order is indeterminate for your case.
Also, dynamic allocations might be deferred:
It is implementation-defined whether dynamic initialization happens-before the first statement of the main function
So it is possible that proper initialization might happen after the first statement of the main function, or at least before one of the variablea are ODR used.
Related
My understanding is that the order of destruction of objects with static storage duration is the inverse of the order of their initialization.
In this code snippet:
#include <iostream>
class LogValuesObj {
public:
LogValuesObj() {
std::cout << "LogValuesObj" << std::endl;
}
~LogValuesObj() {
std::cout << "~LogValuesObj" << std::endl;
}
};
void logValues() {
static LogValuesObj o;
std::cout << "logValues function called" << std::endl;
}
class EarlyInitLogValues {
public:
EarlyInitLogValues() {
std::cout << "EarlyInitLogValues" << std::endl;
logValues();
}
~EarlyInitLogValues() {
std::cout << "~EarlyInitLogValues" << std::endl;
}
};
EarlyInitLogValues e;
int main() {
return 0;
}
The output on my compiler is:
EarlyInitLogValues
LogValuesObj
logValues function called
~EarlyInitLogValues
~LogValuesObj
In this case, the destruction order is the same as the init order, I expected it to be reversed. If both the global 'e' and the function static local 'o' have static storage duration, why is the destruction order not reversed?
It is well-known that objects with static storage duration are destroyed in the reverse order of their construction. But to be more specific—and since it matters in your case—they are destroyed in the reverse order of the completion of their initialization. See [basic.start.term]/3.
In your case, the initialization of o will complete before the initialization of e. Therefore, e is destroyed before o.
I'm creating a static variable 'a' inside a member function getobj() and returning it by reference and capture the reference in b. And I modify the same static variable 'a' in another member function mod(). When I print b, I should be expecting '2' right? Why isn't the static variable 'a' not modified to 2?
#include <iostream>
using namespace std;
class Test {
public:
int& getobj() {
static int a = 1;
return a;
}
void mod() {
static int a = 2;
}
};
int main(int arc, char* args[]) {
Test t;
int &b = t.getobj();
cout << "printing b first time and its value is expected : " << b << endl;
t.mod();
cout << "printing b second time after modifying and its value has not changed : " << b << endl;
return 0;
}
Output observed is
printing b first time and its value is expected : 1
printing b second time after modifying and its value has not changed : 1
The variable a in getobj() and the variable a in mod() are in different scope and are different things.
Therefore, modification to a in mod() won't affect a in getobj().
You could achieve your aim with the following piece of computational devilry:
void mod() {
static int& a = getobj();
a = 2;
}
Currently you have two different ints, both with static storage. Changing one will not change the other.
But did you want to use a class member variable instead (which is the normal thing to do), perhaps even without static storage duration?
There is this code:
#include <iostream>
const int c = 3;
struct A {
static int f() { return c; }
static const int c = 2;
};
int main() {
std::cout << A::f() << std::endl; // 2
return 0;
}
How does it happen that variable c defined inside class A is used in function f instead of variable c defined in global scope although global variable c is declared first?
It does not matter which variable is declared first: if a class has a variable with the same name in it, that variable trumps the global variable. Otherwise you could get existing code in a lot of trouble simply by declaring a global variable with a name of one of its member variables!
Of course your class can use scope resolution operator to reference the global c directly:
static int f() { return ::c; }
Now your program will print 3 instead of 2.
Is not a question of declaring order but of variable scope, the used variable are searched before in the current method/function after in the class/struct and a the and in the global context,
example:
#include <iostream>
const int c = 3;
struct A {
static void print() {
int c = 4
std::cout <<"Method Scope:"<< c << std::endl; // 4
std::cout <<"Class/Struct Scope:"<< A::c << std::endl; // 2 here you can use alse ::A::c
std::cout <<"Global Scope:"<< ::c << std::endl; // 3
}
static const int c = 2;
};
struct B {
static void print() {
std::cout <<"Method Scope:"<< c << std::endl; // 2
std::cout <<"Class/Struct Scope:"<< B::c << std::endl; // 2 here you can use alse ::A::c
std::cout <<"Global Scope:"<< ::c << std::endl; // 3
}
static const int c = 2;
};
struct C {
static void print() {
std::cout <<"Method Scope:"<< c << std::endl; // 3
//std::cout <<"Class/Struct Scope:"<< C::c << std::endl; //is inpossible ;)
std::cout <<"Global Scope:"<< ::c << std::endl; // 3
}
};
int main() {
A::print();
B::print();
C::print();
return 0;
}
imagine that you have long code which uses many variables, do you want them to be called instead these from a class to which function belongs? stating:
a or b
in class means
this->a
this->b
and if you want global variable to be visible you have to use it like
::a or ::b inside this function, so via:
static int f() { return ::c; }
From the standard docs, Sec 3.3.1
Every name is introduced in some portion of program text called a declarative region, which is the largest part of the
program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the
same entity. In general, each particular name is valid only within some possibly discontiguous portion of program text
called its scope. To determine the scope of a declaration, it is sometimes convenient to refer to the potential scope of
a declaration. The scope of a declaration is the same as its potential scope unless the potential scope contains another
declaration of the same name. In that case, the potential scope of the declaration in the inner (contained) declarative
region is excluded from the scope of the declaration in the outer (containing) declarative region.
this means that the potential scope is same as the scope of the declaration unless another (inner) declaration occurs. If occurred, the potential scope of the outer declaration is removed and just the inner declaration's holds, so your global variable is hidden.
Can there be a member variable in a class which is not static but which needs to be defined
(as a static variable is defined for reserving memory)? If so, could I have an example? If not, then why are static members the only definable members?
BJARNE said if you want to use a member as an object ,you must define it.
But my program is showing error when i explicitly define a member variable:
class test{
int i;
int j;
//...
};
int test::i; // error: i is not static member.
In your example, declaring i and j in the class also defines them.
See this example:
#include <iostream>
class Foo
{
public:
int a; // Declares and defines a member variable
static int b; // Declare (only) a static member variable
};
int Foo::b; // Define the static member variable
You can now access a by declaring an object of type Foo, like this:
Foo my_foo;
my_foo.a = 10;
std::cout << "a = " << my_foo.a << '\n';
It's a little different for b: Because it is static it the same for all instance of Foo:
Foo my_first_foo;
Foo my_second_foo;
Foo::b = 10;
std::cout << "First b = " << my_first_foo.b << '\n';
std::cout << "Second b = " << my_second_foo.b << '\n';
std::cout << "Foo::b = " << Foo::b << '\n';
For the above all will print that b is 10.
in that case, you would use the initialization list of test's constructor to define the initial values for an instance like so:
class test {
int i;
int j;
//...
public:
test() : i(-12), j(4) {}
};
That definition reserves space for one integer, but there'll really be a separate integer for every instance of the class that you create. There could be a million of them, if your program creates that many instances of test.
Space for a non-static member is allocated at runtime each time an instance of the class is created. It's initialized by the class's constructor. For example, if you wanted the integer test::i to be initialized to the number 42 in each instance, you'd write the constructor like this:
test::test(): i(42) {
}
Then if you do
test foo;
test bar;
you get two objects, each of which contains an integer with the value 42. (The values can change after that, of course.)
Given this code:
#include <iostream>
using namespace std;
class Foo {
public:
Foo () { c = 'a'; cout << "Foo()" << endl; }
Foo (char ch) { c = ch; cout << "Foo(char)" << endl; }
~Foo () { cout << "~Foo()" << endl; }
private:
char c;
};
class Bar : public Foo {
public:
Bar () { cout << "Bar()" << endl; }
Bar (char ch) : Foo(ch) { cout << "Bar(char)" << endl; }
~Bar () { cout << "~Bar()" << endl; }
};
Foo f1; static Bar b1;
int main()
{
Bar b2;
{
static Foo f2('c');
Foo f3;
Bar b3 ('d');
}
return 0;
}
(You can just paste this directly into a compiler)
The first part of my expected sample output is correct:
Foo()
Foo()
Bar()
Foo()
Bar()
Foo(char)
Foo()
Foo(char)
Bar(char)
~Bar()
~Foo
~Foo()
~Bar()
~Foo()
~Foo()
But I get the destructor output of the two static objects static Bar b1; and static Foo f2('c'); wrong.
The correct answer for the last part is:
~Bar()
~Foo()
~Foo()
I get:
~Foo()
~Bar()
~Foo()
This is my reasoning:
I understand that all local objects are destructed before static objects. Of the two remaining static objects static Bar b1; and static Foo f2('c');, static Foo f2('c'); appears last, so it is destructed first, because destructors are called in the reverse order of their creation.
But static Foo f2('c'); isn't destructed first, static Bar b1; is. Why?
Modified you program :
#include <iostream>
using namespace std;
class Foo {
public:
Foo () { c = 'a'; cout << "Foo()" << endl; }
Foo (char ch) { c = ch; cout << "Foo(char)" << ch << endl; }
~Foo () { cout << "~Foo()"<< c << endl; }
protected:
char c;
};
class Bar : public Foo {
public:
Bar () { cout << "Bar()" << endl; }
Bar (char ch) : Foo(ch) { cout << "Bar(char)" << ch << endl; }
~Bar () { cout << "~Bar()" << c << endl; }
};
Foo f1('a'); static Bar b1('b');
int main()
{
Bar b2('c');
{
static Foo f2('d');
Foo f3('e');
Bar b3 ('f');
}
return 0;
}
Which generates the following output in g++ 4.5.2:
Foo(char)a
Foo(char)b
Bar(char)b
Foo(char)c
Bar(char)c
Foo(char)d
Foo(char)e
Foo(char)f
Bar(char)f
~Bar()f
~Foo()f
~Foo()e
~Bar()c
~Foo()c
~Foo()d
~Bar()b
~Foo()b
~Foo()a
You see that the last destructed one is the non-static global variable Foo f1.
EDIT:
As the others mentioned, the initialization order of variables with static storage duration is unspecific if the variables are from different translation units, but they can be defined when they are in the same translation unit.
Initialization by constructor calls (as in this examples) are called dynamic initialization, and
Dynamic initialization of a non-local variable with static storage
duration is either ordered or unordered. Definitions of explicitly
specialized class template static data members have ordered
initialization. Other class template static data members (i.e.,
implicitly or explicitly instantiated specializations) have unordered
initialization. Other non-local variables with static storage duration
have ordered initialization. Variables with ordered initialization
defined within a single translation unit shall be initialized in the
order of their definitions in the translation unit.
It is implementation-defined whether the dynamic initialization of a
non-local variable with static storage duration is done before the
first statement of main. If the initialization is deferred to some
point in time after the first statement of main, it shall occur before
the first odr-use (3.2) of any function or variable defined in the
same translation unit as the variable to be initialized.
The initialization of local static variables is specified as
... such a variable
is initialized the first time control passes through its declaration; ...
And as the destruction of variables with static storage duration should be in the reverse order of their construction, so the order of construction and destruction of the variables with types Foo and Bar in this example is in fact defined.
Again, when you have multiple translation, you'd better not to rely on the order of initialization.
See this C++ FAQ entry, the initialization order for static objects is undefined. Don't rely on it.