static variable in the class declaration or definition? - c++

I am new to C++.
I have a class like this:
class CodeTest
{
private:
static const int TOTAL=100;
};
Is TOTAL a declaration or a definition?
When I was reading Scott Meyer's book, it was mentioned that in the implementation file we need to define something like:
const int CodeTest::TOTAL;
Why is this required?

The declaration in an implementation file outside of the header is required because otherwise every translation unit that includes this header would define its own object (that is, its own storage for the variable).
This would violate the One Definition Rule. A consequence would be e.g. that if the variable was changed in one translation unit, this change would be invisible to other translation units. Now, this isn’t that relevant since the variable is constant. However, taking its address would also yield different pointers in different translation units.

Since this stirred up some controversy, I looked in the standard, and #Nawaz is right, I was wrong.
9.4.2/2
If a static data member is of const integral type [...]. 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.
So what you have there is a declaration, and the variable is initialized to a value. Outside the class you must define the variable, but not assign a value to it.
The part with const integral type only applies to this particular case - i.e. you can initialize said type inside the class, but all static data members must be defined outside.
To answer the question:
Regardless of whether the definition is or isn't required outside the class (depending on whether you use the member or not), whatever is inside the class (initialized or not) is just a declaration.

First part of the question:
This line: static const int TOTAL=100; is a declaration followed by an initialisation.
TOTAL is an identifier.
Second part of the question
const int CodeTest::TOTAL is required to initialize the variable.

static const int TOTAL=100; // is a declaration followed by an initialisation.
From the C++ standard section 3.1:
A declaration introduces names into a translation unit or redeclares names introduced by previous declarations. A declaration specifies the interpretation and attributes of these names.
The next paragraph states that a declaration is a definition unless...... it declares a static member within a class definition:
struct X
{
int a; // defines a
static int b; // declares b
};
You can read more about definition and declaration here: SO: What is the difference between a definition and a declaration?

Related

Why we need a separate definition for a static const data member?

Hello if I have a static const data member then I can provide an in-class initializer for it and I don't need to define it again outside of the class body.
But that is true only if that constant is used within the class scope and if used outside, a separate definition outside must be supplied otherwise any reference to it causes a link-time error: "undefined reference to static object: x".
struct Foo{
static int const sz_ = 100;
std::array<int, sz_> ai_100{};
};
//int const Foo::sz_;
int main(){
float pts[Foo::sz_]{}; // ok
void bar(int const&); // defined later on
bar(Foo::sz_); // undefined reference to Foo::sz_
}
void bar(int const&){
//do_something
}
Why when used the static const data member sz_outside of the class scope as the array size is OK?
Why when passing sz to function bar which takes an l-value reference to const the linker fails to link and complain about the definition of Foo::sz_?
The function bar takes an l-value reference to const int& so it can be initialized from an r-value so why it matters about the definition of the initializer Foo::sz_?
Why we need a separate definition for a static const data member?
First, we must remember the One Definition Rule. It's actually a set of rules, but a simplified version of the rule that we are interested in this context is: There must be exactly one definition of every variable.
Secondly, we should consider that classes are often used in more than one translation unit.
If the declaration of the static member variable was a definition, then every translation unit that includes contains the class definition would contain that variable definition. That would be contrary to the ODR, and the linker wouldn't know what to do.
As such, there must be a separate definition of the variable which allows the class definition to be included into multiple translation unit while keeping the separate variable definition in one translation unit.
While the language implementations of past may not have been able to deal with multiple definitions (back before templates were in C++), these days they are, and the language has been expanded (in C++17) to allow inline definitions of variables. inline keyword has the same meaning for variable as it has for functions: It relaxes the One Definition Rule allowing (and also requiring) the variable to be defined in every TU (where it is odr-used).
Mostly for historical reasons. Staring with C++17, you can have inline data members. And constexpr members are inline by default.
Your non-linking example can be simplified to:
struct Foo{
static int const sz_ = 100;
};
int main(){
int const *p = &Foo::sz_; // undefined reference to Foo::sz_
}
In other words, if we take the address of Foo::sz_, or assign a reference to it (which is a very similar operation, under the hood), then we need to define int const Foo::sz_; somewhere.
Why is this? Well, if we just use the value of Foo::sz_, then the compiler doesn't need a variable. It can just use 100 as, effectively, a literal. But if we want to take the address of it then we need an actual variable to refer to.

Why is "inline" required on static inline variables?

C++17 allows static member variables to be defined thus:
class X {
public:
static inline int i = 8;
};
What is the rationale behind requiring the inline specification? Why not simply allow programmers to write
static int i = 8;
in the class?
Without inline, it's explicitly stated as only a declaration. As specified in [class.static.data]/2
The declaration of a non-inline static data member in its class
definition is not a definition and may be of an incomplete type other
than cv void. The definition for a static data member that is not
defined inline in the class definition shall appear in a namespace
scope enclosing the member's class definition.
The rationale is most probably to keep legacy code intact and valid. Recall that we could initialize integral constants in the class definition itself since about forever. But odr-using them still required an out-of-class definition in some translation unit.
So to makes such variables implicitly inline could be problematic in existing codebases. The committee is always thinking about backwards compatibility when core language features are added.
For instance, consider this valid C++03 class definition:
struct foo {
static const int n = 3;
double bar[n];
};
n can be used as a constant expression to define the extent of bar, and it's not considered an odr-use. Nowadays we'd write it as constexpr1, however that above is still valid. But there may be cases were n would have to be odr-used (imagine its address taken, or a reference bound to it, etc). They are probably not many, and probably not common, but certain API's have crazy requirements that would end up necessitating this
const int foo::n;
to appear in some translation unit.
Now, if static inline int i = 8; was suddenly implicitly inline, the definition above (that is in an existing code base) would be an odr-violation. Now previously well-formed code, is ill-formed. So it's best to allow only explicit inline to take effect here, since only new code will actually have it.
1 One could argue that static constexpr variables may have the same issue (and yet they are implicitly inline). But IIRC their original wording allowed this change without potentially breaking existing code. It was essentially already "inline" by everything but name.

Confused about declaration, definition [duplicate]

This question already has answers here:
Variable declaration vs definition
(3 answers)
What is the difference between a definition and a declaration?
(27 answers)
Closed 5 years ago.
In the book C++ Primer, it states:
A variable definition consists of a type specifier, followed by a list of one or more variable names separated by commas, and ends with a semicolon.
Each name in the list has the type defined by the type specifier.
A definition may (optionally) provide an initial value for one or more of the name it defines.
Now my confusion is that, I've always thought that for built-in types like int, double, float, etc. If I don't explicitly initialize the variable, then that's simply a declaration. For example:
int a; //i thought that this would just be a declaration
int a = 45; //while built-in types with explicit initialization would be a
//definition
Especially, since default initialization states that:
The value of an uninitialized variable of a built-in type is undefined.
(when inside a function)
Yet the book says:
int a; //is a definition (both a declaration and definition)
int b; //is a definition. yet the variable b is undefined.
So now i'm kind of confused as to what constitutes a declaration and what
constitutes a definition? if having and not having an explicit initialization is not the determining factor.
I know the difference between a declaration and definition when it comes to functions/class. That to use a function/class in more than one file requires declarations that are separate from the function's definition.
Where we define the function in only one file (header file). And that other files that use that function/class must declare (not define) when using that class/function.
In addition, I know that:
A declaration specifies the type and name of a variable and makes a name known to the program.
While, a definition creates the associated entity and allocates storage for that particular variable.
But still, i'm a bit puzzled about when something is a definition vs a declaration when it comes built-in types. Basically all built in types with or without an initializer is both a declaration and a definition?
Example:
int x;
double y;
char z;
float g;
int a; is both a declaration (the variable can be used) and a definition (it has its own memory) but if it is an automatic variable, it is not initialized.
extern int a; is a mere declaration and is not a definition.
From here:
Most of the time, when you declare a variable, you are also providing
the definition. What does it mean to define a variable, exactly? It
means you are telling the compiler where to create the storage for
that variable. For example, if you write:
int x;
int main()
{
x = 3;
}
The line int x; both declares and defines the variable; it effectively
says, "create a variable named x, of type int. Also, the storage for
the variable is that it is a global variable defined in the object
file associated with this source file
this is a part from site more relevant to your question
please refer to the link for further your misconception will be hopefully cleared
http://www.cprogramming.com/declare_vs_define.html

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 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.