There is a static member in a struct, because it is needed in the destructor.
struct Form
{
// ...
~Form()
{
// access World here
}
static btDynamicsWorld *World;
};
Is there a way to initialize this static member from within another function?
void ModulePhysics::Init()
{
// ...
btDynamicsWorld *Form::World = /* ... */;
}
My current code results in those two compiler errors.
Error 1 error C2655: 'Form::World' : definition or redeclaration illegal in current scope
Error 2 error C2086: 'btDynamicsWorld *Form::World' : redefinition
No, you can't. But you can initialize it to NULL, and in the function, if it is NULL, do the real initialization.
Edit: Provide an example:
void ModulePhysics::Init()
{
// ...
if(Form::World == NULL)
{
// The real initialization
}
}
Somewhere, on file scope (in the C file, not in the header!):
btDynamicsWorld* Form::World = NULL;
No you can't.
The declaration of a static data member in the member list of a class is not a definition. You must define the static member outside of the class declaration, in namespace scope.
Here you can get a more detailed description of how and where you can initialize static class variables.
in the init() method remove the type in front of the static variable.
it should solve your issue, I hope.
1) All static class members (except integral members initialized immediately in the class definition) should also be defined outside (preferrably in a .cpp file, so that the definition is processed only once by compiler). For example:
// form.h
struct Form
{
static btDynamicsWorld *World;
};
// form.cpp
// You can initialize World here as well if you want to,
// but you don't have to, as long as it's not const.
// However, it is generally a good idea to initialize
// pointers to NULL (or nullptr in C++11).
btDynamicsWorld *Form::World;
This can only be done at global scope. If you don't do this, you will get linker errors (undefined symbol) if you try referencing this variable.
2) What you are seemingly trying to do is not "initialize", but just assign to the static member. You are doing it almost correctly, but you don't need to redeclare the type:
void ModulePhysics::Init()
{
Form::World = /* ... */;
}
3) I don't really see why do you need to make anything static to access it from the destructor. Destructor is responsible for deleting instance variables, but they are not yet deleted when the destructor's body is executing. So you may just as well use a "normal" class member, unless you are planning to share its value across different class instances.
Related
I have not found a way to initialize the class member succesfully inside the constructor and I can not figure out why.
I have a header file:
#pragma once
struct STATE_MOUSE {
bool moving;
int left_button;
int right_button;
int middle_button;
bool scroll_up;
bool scroll_down;
};
class Message {
private:
static STATE_MOUSE state_mouse;
public:
Message();
~Message();
};
Then I have a source file:
#include "message.hpp"
STATE_MOUSE Message::state_mouse = {false, 0, 0, 0, false, false};
Message::Message() {
//Would like to initialize state_mouse here somehow.
}
Message::~Message() {
}
Now to the issue. This set up seems to work. However I am used to initialize members inside a constructor and I have not found a way to do that with this static struct member.
The following method does not work, could someone explain why?
state_mouse.moving = false;
When you declare a member as static it will belong to the class with only one instance and not to the objects of the class, therefore you cannot initialize it inside the constructor. The constructor is a special member function which mainly exists to initialize the non static members of a new object.
Note that a static member is shared by all objects of the class and when an object changes it, the change can be seen from all other objects of the same class. If this is what do you want to achieve, then the method you shown is good.
Static member variables are not associated with each object of the class. It is shared by all objects.
If you declare a static variable inside the class then you should define it in the cpp file, otherwise, you can get error undefined reference.
Note that if the static member variable is of const int type (e.g. int, bool, char), you can then declare and initialize the member variable directly inside the class declaration in the header file.
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();
}
I have class with static string variable m.
class turbo
{
public:
static string m;
}
if I not declare like defined below I will get error undefined reference turbo::m.
string turbo::m;
Why I should declare it twice? I don't need to declare non static variables second time. Where is logic?
To be honest, I was surprised by this too the first time,
but found the very reasonable reason for it.
while member variables are stored within the object allocated space,
static members are not placed within the object memory space (either heap or stack)
but have a private shared space. just like functions do.
Therefore, declaring the static string m within the class.
is just like saying: there is a shared definition of this somewhere
and the name is turbo::m.
Hope this clears things up.
It's the difference between declaration and definition, very much like declaring a function with a forward reference, e.g.;
int MyFuncion();
and actually defining it with its function body, e.g.,
int MyFunction()
{
return 1;
}
I know you have an object and not a function, but conceptually, the declaration/definition idea is the same.
C++ forbids the definition of non-const static data members in the body of a class ("inline definition"). It becomes more obvious if you try to use an explicit constructor: for example,
class turbo
{
public:
static string m;
static string s = string("my_str"); // doesn't work
}
Hence, when you write static string m in the body of a class, it is merely a declaration, not a definition. You will have to define it later:
static string turbo::s = string("my_str");
In your case, you are simply invoking the default constructor in the definition:
static string turbo::m; // calls the default constructor
(Like any static variable, initialization occurs at the very start of your program, before main.)
Note that the definition must also occur only once (to avoid multiple definitions), so it must not appear in a header file.
In the class definition you only declare the static variable
class turbo
{
public:
static string m;
}
but it is not yet defined. To define the corresponding object you have to write
string turbo::m;
Now it will exist regardless of whether instances of the class were created.
I have a class that store a collection of types. This types are registered by other class using a static method from the first class.
Here is some code :
in file classA.h
class A {
static void RegisterType(std::string name, bool (*checkType)(Json::Value toCheck));
}
In file classB.h
class B {
static bool CheckType(Json::Value toCheck);
}
In file classB.cpp
// In global scope
A::RegisterType("B", &B::CheckType);
When I do this in classB.cpp my compiler (Visual Studio 2010) think I want to redeclare the A::RegisterType() function.
I try to change return type of A::RegisterType() from void to bool. And then assign the returned value to a variable in classB.cpp :
// In global scope
bool tmp = A::RegisterType("B", &B::CheckType);
This way it does work, but I add a variable in global scope and I don't want to.
How can I call A::RegisterType() from global scope without assign his result to a variable ?
Another question is how can I register the "B" type from classB.cpp ?
There are no "freestanding" function calls in C++ : you can call RegisterType() from another static method (e.g., from main())
A workaround is to mimic a static constructor :
struct StaticInit
{
StaticInit()
{
A::RegisterType("B", &B::CheckType);
}
};
class B
{
// ...
static StaticInit si; // Will force the static initialization
};
You can't call functions in the global scope of a file. It must have a scope that relates to the one of the main() function of your program (as in, if you go up in the call stack, you end up in your main() function), or to the scope of a constructor of a class/struct of which you create a static object.
A cpp file isn't executed. It just contains code that will be compiled.
In your case, you could create a static variable of a custom class in your cpp file whose default constructor calls this function.
From language-lawyer point of view, 3.5 Program and linkage states:
A program consists of one or more translation units (Clause 2) linked together. A translation unit consists of a sequence of declarations.
So you can't have statements in global scope, you have to place your call inside main() or inside a constructor of some static variable as suggested by quantdev.
Generally, CPP sees A::RegisterType("B", &B::CheckType); in global scope as declaration and not invoke it as function call.
So either you have to assign it to a global variable as you mentioned in bool tmp = A::RegisterType("B", &B::CheckType); or you have to do as suggested by quantdev
when I want to have a static pointer as a member of a class I need constexprfor the initialisation with nullptr.
class Application {
private:
constexpr static Application* app = nullptr;
}
Can someone explain me why I need to do that? I cannot find the exact reason why it`s necessary that the static variable has to exist at compile time.
That's because you're initialising it inside the class definition. That's only allowed for constant integral and enumeration types (always) and for constexpr data members (since C++11). Normally, you'd initialise it where you define it (outside the class), like this:
Application.h
class Application {
private:
static Application* app;
}
Application.cpp
Application* Application::app = nullptr;
Note that you need to provide the out-of-class definition even in the constexpr case, but it must not contain an initialiser then. Still, I believe the second case is what you actually want.
If you don't want it to be constexpr (and it's not an integer) then you need to initialise it outside of the class body:
class Application
{
private:
static Application* app;
};
Application* Application::app = nullptr;
Typically, you need to initialise a static member variable outside the class declaration, unless it is const. I think this explains it better than I could.
Static variables do not need to "exist at compile time". But if you want to initialize a static variable inside the class, its value needs to be known at compile time.
However, I do not know the reason for this restriction.