static constant members for array size - c++

MyClass.h
class MyClass
{
public:
static const int cTotalCars;
private:
int m_Cars[cTotalCars];
};
MyClass.cpp
#include "MyClass.h"
const int MyClass::cTotalCars = 5;
The above code doesn't work because it will say "expected constant expression" for the m_Cars array.
class MyClass
{
public:
static const int cTotalCars = 5;
private:
int m_Cars[cTotalCars];
};
The above will work, but I am told that I should always define static members in the CPP file, outside the class definition. What can I do?

Static const members of simple type are a exception to that rule, so you latter code is correct.
This exception is a fairly modern one (from C++98, but not implemented by every compiler until a few years later) so many old-fashioned teachers are not yet aware of it. They prefer the idiom:
class MyClass
{
public:
enum { cTotalCars = 5 };
private:
int m_Cars[cTotalCars];
};
That behaves exactly the same, but makes little sense nowadays.

The above will work, but I am told that I should always define static members in the CPP file, outside the class definition. What can I do?
Well, what you have been suggested to do: define the static members in the CPP. Note that in the code above the static member is not defined even if the value is stated. The proper final code would look like:
// .h (ignoring all but the static member)
class MyClass {
static const int cTotalCars = 5; // declaration and initialization
};
// .cpp
static const int MyClass::cTotalCars; // definition (cannot have value!)
The definition in the .cpp file is what actually reserves the space for the variable when used as an lvalue. For a simple test that verifies that without that line the variable is not defined you can do:
void f( const int & x ) {}
int main() {
f( MyClass::cTotalCars );
}
Without the line in the .cpp file the code above will trigger a linker error pointing to the missing definition of MyClass::cTotalCars. The problem with the code is that it uses the static const member (by the definition of use in the standard), and that requires the member to be defined. While the case of using the constant to define the array size does not constitute use.

I would rather use a #define C_TOTAL_CARS 5, then static const int cTotalCars = C_TOTAL_CARS; and then also, int m_Cars[C_TOTAL_CARS];.

If is was a static int you would need to place it into the .cpp file. You do not need the keyword static in this instance as all you want is a constant. Just use const int cTotalCars = 5;. It is better than #define as you have type info and also it has a symbol that can be viewed in a debugger.

It just can't works if you define size of the array is set in cpp file. All class clients should know the size of class instance but they just have no idea about .cpp file because you only put #include "MyClass.h" in client-files.
In other words - your class definition is varies depending on the cpp-file which is not used while compile files that uses MyClass.

Related

How do I know when and where a static inline in-class-initialised member object is initialised?

Before C++17 you needed to define and/or initialise a non-const class member object separately from the class definition, otherwise you got a linker error:
//MyClass.h
extern int globalInt;
class MyClass
{public:
static int classStaticMemberInt;
};
//MyClass.cpp
int globalInt = 7;
int MyClass::classStaticMemberInt = globalInt;
Choosing this method I know that the MyClass::classStaticMemberInt object is initialised after the "int globalInt". It's defined only once, and I choose where to define it.
After C++17 we have the choice of avoiding writing everything twice, and just doing:
//MyClass.h
extern int globalInt;
class MyClass
{public:
static inline classStaticMemberInt = globalInt;
}
But if I include the "MyClass.h" header in a few compilation units, and I want, for example, to be sure that "int globalInt" is initialised before int MyClass::classStaticMemberInt, how can I know? I imagine the static inline in-class syntax in C++17 essentially tells the compiler to define that variable/object once, "somewhere", but where is that somewhere? For example if I do the following:
// Some cpp
int globalInt = 7; // Global object definition
#include MyClass.h // Include class MyClass,
// which static inline defines classStaticMemberInt
//to be equal to "int globalInt"
Is the class member object guaranteed to have the right value because the preprocessor pastes the class definition after "int globalInt = 7;"?
Also, let's just say that I paste the "MyClass.h" header into another .cpp, because the compiler should 'define' that object only once in one translation unit does it mean that it can choose to define it in the .cpp that I didn't define the global object in? And therefore any care I take to paste the header after the global int definition is pointless?

error: non-const static data member must be initialized out of line

class Solution {
public:
static int m=INT_MIN; // it shows error: non-const static data member must
be initialized out of line.(why?)
using "int m=INT_MIN" is fine.
int func(TreeNode*root){
if(root==NULL){
return 0;
}
int l=max(func(root->left),0);
int r=max(func(root->right),0);
m=max(l+r+root->val,m);
return max(l,r)+root->val;
}
int maxPathSum(TreeNode* root) {
if(root==NULL)
{
return 0;
}
m=INT_MIN;
int x=func(root);
return m;
}
};
I need to update the value of variable m. Therefore I am using static int data type. But the following error is coming.
Using int instead of static int is working fine. But why is static int giving error?
Bjarne Stroustrup explains this here:
A class is typically declared in a header file and a header file is
typically included into many translation units. However, to avoid
complicated linker rules, C++ requires that every object has a unique
definition. That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
As said by Stroustrup, every class needs a unique definition. Now, as we know static members are associated directly with their class. Now consider the two cases:
The static member is also constant, then its initialization is allowed inline because the compiler can make its own optimisations and treat this member as a compile-time constant because it is guaranteed that its value will never change. So, as the value of this member is fixed, the definition of the class with which this member is associated is also fixed. So, the initialization is allowed inline.
The static member is not constant. Then its value can change later on during the execution of the program. So, the compiler can not make compile-time optimisations on this member. Hence, to prevent the complications that may arise while trying to initialize such a member when the class is loaded, inline initialisation of such members is not allowed.
PS: When I heard about this concept the very first time, I was also confused because it is not in accordance with the principle of orthogonality that is a feature desired by programmers. The principle of orthogonality will state that since we can combine int and static; and int and const, we should be able to write static const int and static int in a similar fashion. But this case here is an example of a situation where the developer of a language has to give up orthogonality for the users of the language in exchange of the simplicity of the compilation process.
Have a look at the concept of orthogonality here
To answer OPs question why
class Solution {
public:
int m = INT_MIN;
};
is fine but
class Solution {
public:
static int m = INT_MIN;
};
is not:
In short: Prefixing a data-member with static fundamentally change its meaning.
Without static, the member variable is part of the class and each instance will provide a separate storage for this member variable.
With static, the member variable has only scope of the class but there will be only one global storage.
Respectively, the initialization has different meanings too.
For non-static member variables, it provides a default initialization which constructors may use (or override).
Demonstration by Example:
#include <iostream>
enum ArgCase1 { Case1 };
enum ArgCase2 { Case2 };
class Solution {
public:
int m = 123;
Solution() = default; // will use m(123) implicitly
Solution(ArgCase1) { } // will use m(123) implicitly
Solution(ArgCase2): m(456) { } // default of m ignored
};
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(Solution sol);
std::cout << "sol.m: " << sol.m << '\n';
DEBUG(Solution sol1(Case1));
std::cout << "sol1.m: " << sol1.m << '\n';
DEBUG(Solution sol2(Case2));
std::cout << "sol2.m: " << sol2.m << '\n';
}
Output:
Solution sol;
sol.m: 123
Solution sol1(Case1);
sol1.m: 123
Solution sol2(Case2);
sol2.m: 456
Live Demo on coliru
For static member variables, the initialization would be dangerous. Assuming that a class is declared in a header which is included multiple times, this would result in a violation of the One Definition Rule.
In former times, it was usual to declare the static member variable in the header but to define it in the .cpp-file (which represents the translation unit).
Expample:
solution.h:
#ifndef SOLUTION_H
#define SOLUTION_H
class Solution {
public:
static int m;
};
#endif // SOLUTION_H
solution.cc:
// header of this module:
#include "solution.h"
int Solution::m = 123;
Live Demo on coliru
Since C++17, a new alternative is available – using the keyword inline.
From cppreference.com – static members – Static data members
A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify an initializer. It does not need an out-of-class definition
Example:
solution.h:
#ifndef SOLUTION_H
#define SOLUTION_H
class Solution {
public:
inline static int m = 123;
};
#endif // SOLUTION_H
Live Demo on coliru
The advantage is that there is no .cpp-file needed for this i.e. as it is the class Solution could be provided as header-only source.

c++ class member of same type

I have the following situation:
class Foo
{
public:
static const Foo memberOfFoo;
........
}
So the thing is I can't initialize it in the same line where I declared it, and, I can't initialize it via Initializations List in the constructor, does anyone know what to do?
Put this outside of the class definition then:
const Foo Foo::memberOfFoo = whateverValue;
That is the definition of Foo::memberOfFoo, which can supply an initializer and has to go into the .cpp file (like any other definition of objects, it can only appear once in the whole program, otherwise you will get linker errors).
Sometimes you will find code that doesn't have definitions for its static data members:
struct A {
// sometimes, code won't have an "const int A::x;" anywhere!
static const int x = 42;
};
Omitting the definition like that is valid only if A::x is never address-taken and never passed to reference parameters. A more formal way to say when it is valid to omit the definition is: "When all uses of A::x immediately read the stored value of A::x". That's the case for many static integer constants.
Class statics other than constant integral types need to/can be initialized at the point of definition. You need to declare your (not so)memberOfFoo somewhere, by adding
const Foo Foo::memberOfFoo = /*construct here*/;
This is how you can implement initialization...
class Foo
{
public:
static const Foo memberOfFoo;
Foo(int, double)
{
...
};
};
const Foo Foo::memberOfFoo(42, 3.141592654);
...

Where to place Structs and Enums in C++ class + final constants

I have started reading C++ and I have a question about classes and member variables of type Enum and Struct. Where should I declare Enums/Structs so that I can use them as member variables when I separate header and implementation file? And also, how can I make a final member variable in a C++ class? I am just getting compilation error when adding const int myTest as a member variable, where should I initialize them?
The header file is like a person saying 'I can do this, that and the other' - so put declarations into it - enums, structs, class declarations, constants, ...
The implementation file is like a person saying 'I can do this and this is how I can do it' - it produces a recipe - Actual machine code for the CPU to crunch.
const says - do not change me. To intialise in a class you need:
class X
{
private:
const int y;
public:
X() : y(5) {}
};
for example. If you are learning about C++ const is a very useful tool to prevent you making a multitude of errors.
the simplest solution is to simple declare the enums & structs directly before the class they are a member of:
struct Gizmo
{
int n_;
};
class Foo
{
public:
Gizmo gizmo_;
};
If Gizmo is logically coupled to Foo (eg, if you would never use a Gizmo outside the context of using a Foo), it might also make sense to make Gizmo a nested class:
class Foo
{
public:
struct Gizmo
{
int n_;
};
Gizmo gizmo_;
};
If you want to instantiate a Gizmo declared this way, you can resolve the scope yourself:
Foo::Gizmo gizmo;
Finally, if Gizmo and Foo are not logically coupled, and you might use Gizmos all over the place without needing a Foo, then it probably belongs in its own header file.
gizmo.h
struct Gizmo
{
int n_;
};
foo.h
#include "gizmo.h"
class Foo
{
public:
Gizmo gizmo_;
};
Where should I declare Enums/Structs so that I can use them as member variables when I separate header and implementation file?
You must declare them before their use, that is. before the declaration of the member in the class of their type. Either:
you define them in their own header file and #include that file in your class' header file (before the declaration of your class)
or you define them just before your class
or you define them in your class before the members
I am just getting compilation error when adding const int myTest as a member variable, where should I initialize them?
In the constructor, using initializers. Ie.:
Clazz::Clazz() : my_const_var(0) { ... }
If you're going to add an enum or struct as a member variable of the class, the definition of the enum or struct must be complete before you declare the member. This can either be inside the class, outside of the class but coming before it in the .h header, or in a different .h header that is included before or within the current one.
There shouldn't be any problem declaring a member variable as const, but it places a restriction on how it must be initialized. You must do it in the initializer list of the constructor.
MyClass::MyClass() : myTest(value)
{
}

Initialize static variables in C++ class?

I have noticed that some of my functions in a class are actually not accessing the object, so I made them static. Then the compiler told me that all variables they access must also be static – well, quite understandable so far. I have a bunch of string variables such as
string RE_ANY = "([^\\n]*)";
string RE_ANY_RELUCTANT = "([^\\n]*?)";
and so on in the class. I have then made them all static const because they never change. However, my program only compiles if I move them out of the class: Otherwise, MSVC++2010 complains "Only static constant integral variables may be initialized within a class".
Well that's unfortunate. Is there a workaround? I would like to leave them inside the class they belong to.
They can't be initialised inside the class, but they can be initialised outside the class, in a source file:
// inside the class
class Thing {
static string RE_ANY;
static string RE_ANY_RELUCTANT;
};
// in the source file
string Thing::RE_ANY = "([^\\n]*)";
string Thing::RE_ANY_RELUCTANT = "([^\\n]*?)";
Update
I've just noticed the first line of your question - you don't want to make those functions static, you want to make them const. Making them static means that they are no longer associated with an object (so they can't access any non-static members), and making the data static means it will be shared with all objects of this type. This may well not be what you want. Making them const simply means that they can't modify any members, but can still access them.
Mike Seymour has given you the right answer, but to add...
C++ lets you declare and define in your class body only static const integral types, as the compiler tells. So you can actually do:
class Foo
{
static const int someInt = 1;
static const short someShort = 2;
// etc.
};
And you can't do that with any other type, in that cases you should define them in your .cpp file.
Some answers including even the accepted answer seem to be a little misleading.
You don't have to
Always assign a value to static objects when initializing because that's optional.
Create another .cpp file for initializing since it can be done in the same header file.
You can even initialize a static object in the same class scope just like a normal variable using the inline keyword.
Initialize with no values in the same file
#include <string>
class A
{
static std::string str;
static int x;
};
std::string A::str;
int A::x;
Initialize with values in the same file
#include <string>
class A
{
static std::string str;
static int x;
};
std::string A::str = "SO!";
int A::x = 900;
Initialize in the same class scope using the inline keyword
#include <string>
class A
{
static inline std::string str = "SO!";
static inline int x = 900;
};
Since C++11 it can be done inside a class with constexpr.
class stat {
public:
// init inside class
static constexpr double inlineStaticVar = 22;
};
The variable can now be accessed with:
stat::inlineStaticVar
Static member variables must be declared in the class and then defined outside of it!
There's no workaround, just put their actual definition in a source file.
From your description it smells like you're not using static variables the right way. If they never change you should use constant variable instead, but your description is too generic to say something more.
Static member variables always hold the same value for any instance of your class: if you change a static variable of one object, it will change also for all the other objects (and in fact you can also access them without an instance of the class - ie: an object).
I feel it is worth adding that a static variable is not the same as a constant variable.
using a constant variable in a class
struct Foo{
const int a;
Foo(int b) : a(b){}
}
and we would declare it like like so
fooA = new Foo(5);
fooB = new Foo(10);
// fooA.a = 5;
// fooB.a = 10;
For a static variable
struct Bar{
static int a;
Foo(int b){
a = b;
}
}
Bar::a = 0; // set value for a
which is used like so
barA = new Bar(5);
barB = new Bar(10);
// barA.a = 10;
// barB.a = 10;
// Bar::a = 10;
You see what happens here. The constant variable, which is instanced along with each instance of Foo, as Foo is instanced has a separate value for each instance of Foo, and it can't be changed by Foo at all.
Where as with Bar, their is only one value for Bar::a no matter how many instances of Bar are made. They all share this value, you can also access it with their being any instances of Bar. The static variable also abides rules for public/private, so you could make it that only instances of Bar can read the value of Bar::a;
Just to add on top of the other answers. In order to initialize a complex static member, you can do it as follows:
Declare your static member as usual.
// myClass.h
class myClass
{
static complexClass s_complex;
//...
};
Make a small function to initialize your class if it's not trivial to do so. This will be called just the one time the static member is initialized. (Note that the copy constructor of complexClass will be used, so it should be well defined).
//class.cpp
#include myClass.h
complexClass initFunction()
{
complexClass c;
c.add(...);
c.compute(...);
c.sort(...);
// Etc.
return c;
}
complexClass myClass::s_complex = initFunction();
If your goal is to initialize the static variable in your header file (instead of a *.cpp file, which you may want if you are sticking to a "header only" idiom), then you can work around the initialization problem by using a template. Templated static variables can be initialized in a header, without causing multiple symbols to be defined.
See here for an example:
Static member initialization in a class template
Optionally, move all your constants to .cpp file without declaration in .h file. Use anonymous namespace to make them invisible beyond the cpp module.
// MyClass.cpp
#include "MyClass.h"
// anonymous namespace
namespace
{
string RE_ANY = "([^\\n]*)";
string RE_ANY_RELUCTANT = "([^\\n]*?)";
}
// member function (static or not)
bool MyClass::foo()
{
// logic that uses constants
return RE_ANY_RELUCTANT.size() > 0;
}