Class static type initialization - c++

So I just had a question, In c++11 why do I have to specify the type of a static member to assign to it a value?
Example:
class Player
{
static size_t numOfObj;
public:
Player(){numOfObj++;}
~Player(){numOfObj--;}
}
size_t Player::numOfObj = 0;
In this case why do I have to specify again that numOfObj is of type size_t, can't I just do Player::numOfObj = 0; due to it being already declared?
Thanks in advance.

size_t Player::numOfObj = 0; is syntax for definition. A (non-inline) static variable must be defined exactly once in exactly one translation unit. Not more, and not less (unless the variable is unused).
can't I just do Player::numOfObj = 0; due to it being already declared?
You can do that. But not in the namespace scope because that is syntax of an expression statement. Expression statements may not be in the namespace scope. They are allowed only in a block scope. The meaning of this expression is that the value of the variable is assigned. Assignments can be done as many times and in as many translation units as you like (as long as the type is non-const and assignable).
So, if definition had this syntax, there would be conflict with the syntax already having another meaning. That would be undesirable.

Related

What is the difference between declaration and definition of a variable in C++? [duplicate]

This question already has answers here:
What is the difference between a definition and a declaration?
(27 answers)
Closed 7 years ago.
My question stems from studying Effective C++ by Scott Meyers.
In Item II of that book, following is written :
To limit the scope of a constant to a class, you must make it a member and, to ensure there's at most one copy of the constant, you must make it a static member.
That is correctly written. Then immediately the following example is given :
class GamePlayer {
private:
static const int NumTurns = 5;
int scores[NumTurns];
....
};
Then the following is written pertaining to the above example :
What you see above is a declaration and not a definition of NumTurns.
My First question is : What is the meaning of this statement ?
Immediately after that the following is mentioned :
Usually C++ requires that you provide a definition for anything you use, but class specific constants that are static and of integral type (e.g - integers, chars, bools) are an exception. As long as you don't take their address, you can declare them and use them without providing a definition. If you do take the address of a class constant, or if your compiler incorrectly insists on a definition even if you don't take the address, you provide a separate definition like this :
const int GamePlayer::Numturns; //definition of NumTurns
Why now it is a definition and not a declaration ?
I understand the difference in the context of a function but do not understand it in the context of a regular variable. Also, can someone expand on what the author means by
... if you do take the address of a class constant, or if your ..
part of the above quoted paragraph ?
P.S : I am a relatively newbie in C++.
Just as with functions, variables can have 'purely declarative' declarations, and actual definitions. You're confused because you probably didn't encounter many pure variable declarations before.
int i; // Definition
extern int i, j; // (Re)declares i, and declares j
extern int j = 0; // Defines j (confusing, eh?)
As you're used to with functions, definitions are declarations, but not all declarations are definitions. §3.1/2 reads
A declaration is a definition unless […] it declares a static data
member in a class definition (9.2, 9.4),
Thus in-class static data member declarations are never defining the variables they declare. However, sometimes, a variables definition doesn't have to be present. That is the case when you can use its value directly without necessitating the variables run-time existence.
In technical terms, as long as a static data member (or any entity, for that matter) is not 'odr-used', it doesn't have to be defined. Odr-use for all entities is defined in §3.2/3:
A variable x whose name appears as a potentially-evaluated expression
ex is odr-used by ex unless applying the lvalue-to-rvalue conversion
(4.1) to x yields a constant expression (5.20) that does not invoke
any non-trivial functions and, if x is an object, ex is an element of
the set of potential results of an expression e, where either the
lvalue-to-rvalue conversion (4.1) is applied to e, or e is a
discarded-value expression (Clause 5).
This looks complicated, and it was simpler in earlier versions of the standard. However, it roughly says that the variable is not odr-used by some expression when that expression "immediately" accesses the variables value, and this access yields a constant expression. Meyers example of "taking its address" is only one of many for odr-use.
For some class A and its static data member i,
class A {
static const int i = 57; // Declaration, not definition
};
const int A::i; // Definition in namespace scope. Not required per se.
It is stated here that:
Static const integral data members initialized in the class interface are not addressable variables. They are mere symbolic names for their associated values. Since they are not variables, it is not possible to determine their addresses. Note that this is not a compilation problem, but a linking problem. The static const variable that is initialized in the class interface does not exist as an addressable entity.
What "addressable entity" refers here is "instance" of static const data type. No instance, no address, i.e its only a declaration.
Note that static variables that are explicitly defined in a source file can be linked correctly, though.
class X
{
public:
static int const s_x = 34;
static int const s_y;
};
int const X::s_y = 12;
int main()
{
int const *ip = &X::s_x; // compiles, but fails to link
ip = &X::s_y; // compiles and links correctly
}
... if you do take the address of a class constant, or if your .. part of the above quoted paragraph ?
It means if such a member is odr-used, a definition at namespace scope is still required, but it should not have an initializer.
struct X {
const static int n = 1;
};
const int* p = &X::n; // X::n is odr-used
const int X::n; // ... so a definition is necessary
Why now it is a definition and not a declaration ?
Because this statement causes the compiler to generate an address for the static variable.
Also, can someone expand on what the author means by "if you do take
the address of a class constant":
When you make a pointer point to a variable you take its address.
A short answer is: a declaration says "this thing exists somewhere", and a definition causes the space to be allocated. In your case, you've declared it to be static and const. The compiler may be smart enough to notice that if you only ever use it as a value, it can simply replace that usage with the literal 5. It doesn't need to actually make space for a variable somewhere and fill it with the 5, it can use the 5 directly at compile-time. However, if you take the address of it, the compiler can no longer make that assumption and now needs to put that 5 into somewhere addressable. The compiler needs it to exist in one translation unit (roughly: one cpp file. See also the One Definition Rule.), so now you have to explicitly declare it somewhere.

Why can one initialize non-const and static const member variables but not static member variables?

struct A
{
int a = 5; //OK
const int b = 5; //OK
static const int c = 5; //OK
static int d = 5; //Error!
}
error: ISO C++ forbids in-class initialization of non-const static member 'A::d'
Why is it so? Can someone explain to me the reasoning behind this?
It has to do with where the data is stored. Here's a breakdown:
int: member variable, stored wherever the class instance is stored
const int: same as int
static const int: doesn't need to be stored, it can simply be "inlined" where used
static int: this must have a single storage location in the program...where?
Since the static int is mutable, it must be stored in an actual location somewhere, so that one part of the program can modify it and another part can see that modification. But it can't be stored in a class instance, so it must be more like a global variable. So why not just make it a global variable? Well, class declarations are usually in header files, and a header file may be #included in multiple translation units (.cpp files). So effectively the header file says "there is an int...somewhere." But the storage needs to be put into the corresponding .cpp file (like a global variable).
In the end, this is not really about initialization, but rather the storage. You could leave off the initializer and you'd still not have a valid program until you add this to your .cpp file:
int A::d; // initialize if you want to, default is zero
Without this, references to the static int will be undefined and linking will fail.
Initialization of static const member variables is available for integral and enum types. This feature existed in C++ since the first language standard (C++98). It is needed to facilitate usage of static const members in integral constant expressions (i.e. as compile-time constants), which is an important feature of the language. The reason integral and enum types were singled out and treated in this exceptional fashion is that integral constants are often used in compile-time contexts, which require no storage (no definition) for the constant.
The ability to supply initializers for non-static members is a new (for C++11) feature. It is a completely different feature, even though it looks similar at syntax level. Such initializers are used as construction-time initializers for those class members that were not explicitly initialized by the user.
In other words, it is not correct to lump these two features (initializers for static and non-static members) together. These two features are completely different. They are based on completely unrelated internal mechanics. Your question essentially applies the first feature: how come non-const static members cannot be initialized in-class? It is basically a C++98 question and the most likely answer to it is that there was never any reason to treat non-const static members in such an exceptional way. Non-const static members are treated in accordance with the general rules: they require a separate definition and the initializer should be provided at the point of definition.

Why can you initialize a static const variable inline but not a plain static (C++)

If I were to do this
class Gone
{
public:
static const int a = 3;
}
it works but if do
class Gone
{
public:
static int a = 3;
}
it gives a compile error. Now I know why the second one doesn't work, I just don't know why the first one does.
Thanks in advance.
This trick works only for constant compile-time expressions. Consider the following simple example:
#include <iostream>
class Foo {
public:
static const int bar = 0;
};
int main()
{
std::cout << Foo::bar << endl;
}
It works just fine, because compiler knows that Foo::bar is 0 and never changes. Thus, it optimizes the whole thing away.
However, the whole thing breaks once you take the address of that variable like this:
int main()
{
std::cout << Foo::bar << " (" << &Foo::bar << ")" << std::endl;
}
Linker sends you to fix the program because compile-time constants don't have addresses.
Now, the second case in your example doesn't work simply because a non-constant variable cannot be a constant compile-time expression. Thus, you have to define it somewhere and cannot assign any values in initialization.
C++11, by the way, has constexpr. You can check Generalized constant expressions wiki (or C++11 standard :-)) for more info.
Also, be careful - with some toolchains you will never be able to link program as listed in your first example when optimizations are turned off, even if you never take an address of those variables. I think there is a BOOST_STATIC_CONSTANT macro in Boost to work around this problem (not sure if it works though because I reckon seeing linkage failures with some old gcc even with that macro).
The static const int declaration is legal because you're declaring a constant, not a variable. a doesn't exist as a variable - the compiler is free to optimize it out, replacing it with the declared value 3 anywhere a reference to Gone::a appears. C++ allows the static initialization in this restricted case where it's an integer constant.
You can find more details, including an ISO C++ standard citation here.
Initialization of variables has to be done at the point of definition, not the point of declaration in the general case. Inside the class brackets you only have a declaration and you need to provide a definition in a single translation unit*:
// can be in multiple translation units (i.e. a header included in different .cpp's)
struct test {
static int x; // declaration
static double d; // declaration
};
// in a single translation unit in your program (i.e. a single .cpp file)
int test::x = 5; // definition, can have initialization
double test::d = 5.0; // definition
That being said, there is an exception for static integral constants (and only integral constants) where you can provide the value of the constant in the declaration. The reason for the exception is that it can be used as a compile-time constant (i.e. to define the size of an array), and that is only possible if the compiler sees the value of the constant in all translation units where it is needed.
struct test {
static const int x = 5; // declaration with initialization
};
const int test::x; // definition, cannot have initialization
Going back to the original question:
Why is it not allowed for non-const integers?
because initialization happens in the definition and not declaration.
Why is it allowed for integral constants?
so that it can be used as a compile-time constant in all translation units
* The actual rules require the definition whenever the member attribute is used in the program. Now the definition of used is a bit tricky in C++03 as it might not be all that intuitive, for example the use of that constant as an rvalue does not constitute use according to the standard. In C++11 the term used has been replaced with odr-used in an attempt to avoid confusion.
A static const is defined in the class definition since everybody that uses the code need to know the value at compile time, not link time. An ordinary static is actually only declared in the class definition, but defined once, in one translation unit.
I seem to recall that originally (ARM) it was not allowed, and we used to use enum to define constants in class declarations.
The const case was explicitly introduced so as to support availability of the value in headers for use in constant expressions, such as array sizes.
I think (and please comment if I have this wrong) that strictly you still need to define the value:
const int Gone::a;
to comply with the One Definition Rule. However, in practice, you might find that the compiler optimises away the need for an address for Gone::a and you get away without it.
If you take:
const int* b = &Gone::a;
then you might find you do need the definition.
See the standard, $9.4.2:
ISO 1998:
"4 If a static data member is of const integral or const enumeration
type, its declaration in the class definition can specify a
constantinitializer which shall be an integral constant expression
(5.19). In that case, the member can appear in integral constant
expressions within its scope. The member shall still be defined in a
namespace scope if it is used in the program and the namespace scope
definition shall not contain an initializer."
Draft for c++11:
"3 If a static data member is of const effective literal type, its
declaration in the class definition can specify a constant-initializer
brace-or-equal-initializer with an initializer-clause that is an
integral constant expression. A static data member of effective
literal type can be declared in the class definition with the
constexpr specifier; if so, its declaration shall specify a
constant-initializer brace-or-equal-initializer with an
initializerclause that is an integral constant expression. In both
these cases, the member may appear in integral constant expressions.
The member shall still be defined in a namespace scope if it is used
in the program and the namespace scope definition shall not contain an
initializer."
I am not sure entirely what this covers, but I think it means that we can now use the same idiom for floating point and possibly string literals.

Why does declaring a "static const" member in a header file cause linker errors?

I have a class declaration(.h file) like so:
struct MyClass {
static const uint32_t SIZE = sizeof(MyType);
};
When linking my program together, I get linker errors for MyClass::SIZE. nm confirms that the symbol is undefined. http://forums.devshed.com/c-programming-42/linker-errors-undefined-reference-to-static-member-data-193010.html seems to address my problem, indicating that "class static objects must also be declared outside any function or class just like normal globals."
I have two questions:
Is this explanation valid for my case? If so, can you explain in a little more detail why this is true?
What's the best way to fix it? I'd like to keep this member's initialization entirely in the .h file.
Your problem may have nothing to do with someone taking the address of your variable. It could simply be the compiler opting not to use the variable as a constant expression even though it could. For example:
f(int const&);
struct X { enum { enum_val = 42 }; static int const static_mem = 42; };
f(5);
f(X::enum_val);
f(X::static_mem);
In the first two cases the compiler is required to use the input as a constant expression and the const& can be initialized with such. The last case however is different. Even though your intent is probably to use static_mem as a constant expression, and its completely legitimate to do so, the compiler is free to do otherwise and some will actually create a reference to the variable itself. This is "use" of the variable and thus you're required to have a definition of that variable somewhere in the program.
There's two ways to fix this issue:
1) Add a definition to your program.
2) Use enum instead:
struct X
{
enum { static_mem = ? };
};
The first solution is necessary if you ever do intend that taking the address of your variable be possible. Chances are though that you did not or you would have created that definition already. The later solution forces the compiler to use X::static_mem as a constant expression since enum members don't actually exist as objects in the program. Based on your last statement in your question, I'm betting this is the solution you really want.
The standard requires a definition for a static member integral constant only if its address is taken, otherwise the declaration with an initializer (what you have) is enough. That linker error message should mention which object/function takes an address of MyClass::SIZE.
Quoting myself from No definition available for static const member with initializer?
And from 9.4.2/4:
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).
In that case, the member can appear in
integral constant expressions within
its scope. The member shall still be
defined in a namespace scope if it is
used in the program and the namespace
scope definition shall not contain an
initializer.
From these references we can infer ("...shall still be defined..." in 9.4.2/4) that if it's not defined then the program isn't well-formed.
#David Rodríguez - dribeas points out that you must be taking the address of the static member in your program somewhere. If you can avoid taking the address then there's no need for the definition in the implementation file (alternately you aren't taking the address and have a buggy compiler). Otherwise you must have the definition.
If you've to do this:
//.h file
struct MyClass
{
static const uint32_t SIZE = sizeof(MyType); //this is declaration!
};
//.cpp file
const uint32_t MyClass::SIZE; //this is definition - necessary!
Most likely, but without any error messages, it's hard to say.
Use a static const int. You can initialize it in the header, and you don't need to declare it in the cpp.

How to declare a static const char* in your header file?

I'd like to define a constant char* in my header file for my .cpp file to use. So I've tried this:
private:
static const char *SOMETHING = "sommething";
Which brings me with the following compiler error:
error C2864: 'SomeClass::SOMETHING' :
only static const integral data
members can be initialized within a
class
I'm new to C++. What is going on here? Why is this illegal? And how can you do it alternatively?
NB : this has changed since C++11, read other answers too
You need to define static variables in a translation unit, unless they are of integral types.
In your header:
private:
static const char *SOMETHING;
static const int MyInt = 8; // would be ok
In the .cpp file:
const char *YourClass::SOMETHING = "something";
C++ standard, 9.4.2/4:
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. In that
case, the member can appear in
integral constant expressions within
its scope. The member shall still be
defined in a namespace scope if it is
used in the program and the namespace
scope definition shall not contain an
initializer.
To answer the OP's question about why it is only allowed with integral types.
When an object is used as an lvalue (i.e. as something that has address in storage), it has to satisfy the "one definition rule" (ODR), i.e it has to be defined in one and only one translation unit. The compiler cannot and will not decide which translation unit to define that object in. This is your responsibility. By defining that object somewhere you are not just defining it, you are actually telling the compiler that you want to define it here, in this specific translation unit.
Meanwhile, in C++ language integral constants have special status. They can form integral constant expressions (ICEs). In ICEs integral constants are used as ordinary values, not as objects (i.e. it is not relevant whether such integral value has address in the storage or not). In fact, ICEs are evaluated at compile time. In order to facilitate such a use of integral constants their values have to be visible globally. And the constant itself don't really need an actual place in the storage. Because of this integral constants received special treatment: it was allowed to include their initializers in the header file, and the requirement to provide a definition was relaxed (first de facto, then de jure).
Other constant types has no such properties. Other constant types are virtually always used as lvalues (or at least can't participate in ICEs or anything similar to ICE), meaning that they require a definition. The rest follows.
With C++11 you can use the constexpr keyword and write in your header:
private:
static constexpr const char* SOMETHING = "something";
Notes:
constexpr makes SOMETHING a constant pointer so you cannot write
SOMETHING = "something different";
later on.
Depending on your compiler, you might also need to write an explicit definition in the .cpp file:
constexpr const char* MyClass::SOMETHING;
The error is that you cannot initialize a static const char* within the class. You can only initialize integer variables there.
You need to declare the member variable in the class, and then initialize it outside the class:
// header file
class Foo {
static const char *SOMETHING;
// rest of class
};
// cpp file
const char *Foo::SOMETHING = "sommething";
If this seems annoying, think of it as being because the initialization can only appear in one translation unit. If it was in the class definition, that would usually be included by multiple files. Constant integers are a special case (which means the error message perhaps isn't as clear as it might be), and compilers can effectively replace uses of the variable with the integer value.
In contrast, a char* variable points to an actual object in memory, which is required to really exist, and it's the definition (including initialization) which makes the object exist. The "one definition rule" means you therefore don't want to put it in a header, because then all translation units including that header would contain the definition. They could not be linked together, even though the string contains the same characters in both, because under current C++ rules you've defined two different objects with the same name, and that's not legal. The fact that they happen to have the same characters in them doesn't make it legal.
class A{
public:
static const char* SOMETHING() { return "something"; }
};
I do it all the time - especially for expensive const default parameters.
class A{
static
const expensive_to_construct&
default_expensive_to_construct(){
static const expensive_to_construct xp2c(whatever is needed);
return xp2c;
}
};
If you're using Visual C++, you can non-portably do this using hints to the linker...
// In foo.h...
class Foo
{
public:
static const char *Bar;
};
// Still in foo.h; doesn't need to be in a .cpp file...
__declspec(selectany)
const char *Foo::Bar = "Blah";
__declspec(selectany) means that even though Foo::Bar will get declared in multiple object files, the linker will only pick up one.
Keep in mind this will only work with the Microsoft toolchain. Don't expect this to be portable.
There is a trick you can use with templates to provide H file only constants.
(note, this is an ugly example, but works verbatim in at least in g++ 4.6.1.)
(values.hpp file)
#include <string>
template<int dummy>
class tValues
{
public:
static const char* myValue;
};
template <int dummy> const char* tValues<dummy>::myValue = "This is a value";
typedef tValues<0> Values;
std::string otherCompUnit(); // test from other compilation unit
(main.cpp)
#include <iostream>
#include "values.hpp"
int main()
{
std::cout << "from main: " << Values::myValue << std::endl;
std::cout << "from other: " << otherCompUnit() << std::endl;
}
(other.cpp)
#include "values.hpp"
std::string otherCompUnit () {
return std::string(Values::myValue);
}
Compile (e.g. g++ -o main main.cpp other.cpp && ./main) and see two compilation units referencing the same constant declared in a header:
from main: This is a value
from other: This is a value
In MSVC, you may instead be able to use __declspec(selectany)
For example:
__declspec(selectany) const char* data = "My data";
Constant initializer allowed by C++ Standard only for integral or enumeration types. See 9.4.2/4 for details:
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). In that
case, the member can appear in integral constant expressions. The member shall still be defined in a name-
space scope if it is used in the program and the namespace scope definition shall not contain an initializer.
And 9.4.2/7:
Static data members are initialized and destroyed exactly like non-local objects (3.6.2, 3.6.3).
So you should write somewhere in cpp file:
const char* SomeClass::SOMETHING = "sommething";
To answer the why question, integral types are special in that they are not a reference to an allocated object but rather values that are duplicated and copied. It's just an implementation decision made when the language was defined, which was to handle values outside the object system and in as efficient and "inline" a fashion as possible.
This doesn't exactly explain why they are allowed as initializors in a type, but think of it as essentially a #define and then it will make sense as part of the type and not part of the object.