I want to define array in class:
h:
class A
{
protected:
static const int TABLE[];
}
cpp:
const int A::TABLE[5] = {1, 2, 3, 4, 5};
This should be a const array all object of type class A will use.
Should I define it in the header file? what is the best practice for this?
I sew previous questions and some suggested to define it with "extern". like this:
h:
class A
{
protected:
extern const int TABLE[];
}
cpp:
const int A::TABLE[5] = {1, 2, 3, 4, 5};
it is insted of static?
............................
There are two options here. Either we can define it inside the class using the inline keyword with C++17 & onwards or declare it inside the class and then provide an out of class definition in exactly on source file.
Method 1
Here we use inline with C++17.
header.h
#pragma once
class A
{
protected:
//------vvvvvv---------------------------->inline used here with c++17
inline static const int TABLE[] = {1, 2, 3, 4, 5};
};
Demo method 1
Method 2
Here we declare it inside the class and then define it outside the class in exactly one source file.
header
#pragma once
class A
{
protected:
static const int TABLE[5];
};
source file
#include "header.h"
const int A::TABLE[5] = {1, 2, 3, 4, 5};
Demo method 2
Note that instead of using built in array I would recommend using std::array.
Related
What is the best way to initialize a private, static data member in C++? I tried this in my header file, but it gives me weird linker errors:
class foo
{
private:
static int i;
};
int foo::i = 0;
I'm guessing this is because I can't initialize a private member from outside the class. So what's the best way to do this?
The class declaration should be in the header file (Or in the source file if not shared).
File: foo.h
class foo
{
private:
static int i;
};
But the initialization should be in source file.
File: foo.cpp
int foo::i = 0;
If the initialization is in the header file then each file that includes the header file will have a definition of the static member. Thus during the link phase you will get linker errors as the code to initialize the variable will be defined in multiple source files.
The initialisation of the static int i must be done outside of any function.
Note: Matt Curtis: points out that C++ allows the simplification of the above if the static member variable is of const integer type (bool, char, char8_t [since C++20], char16_t, char32_t, wchar_t, short, int, long, long long, or any implementation-defined extended integer types, including any signed, unsigned, and cv-qualified variants.). You can then declare and initialize the member variable directly inside the class declaration in the header file:
class foo
{
private:
static int const i = 42;
};
For a variable:
foo.h:
class foo
{
private:
static int i;
};
foo.cpp:
int foo::i = 0;
This is because there can only be one instance of foo::i in your program. It's sort of the equivalent of extern int i in a header file and int i in a source file.
For a constant you can put the value straight in the class declaration:
class foo
{
private:
static int i;
const static int a = 42;
};
Since C++17, static members may be defined in the header with the inline keyword.
http://en.cppreference.com/w/cpp/language/static
"A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify a default member initializer. It does not need an out-of-class definition:"
struct X
{
inline static int n = 1;
};
For future viewers of this question, I want to point out that you should avoid what monkey0506 is suggesting.
Header files are for declarations.
Header files get compiled once for every .cpp file that directly or indirectly #includes them, and code outside of any function is run at program initialization, before main().
By putting: foo::i = VALUE; into the header, foo:i will be assigned the value VALUE (whatever that is) for every .cpp file, and these assignments will happen in an indeterminate order (determined by the linker) before main() is run.
What if we #define VALUE to be a different number in one of our .cpp files? It will compile fine and we will have no way of knowing which one wins until we run the program.
Never put executed code into a header for the same reason that you never #include a .cpp file.
Include guards (which I agree you should always use) protect you from something different: the same header being indirectly #included multiple times while compiling a single .cpp file.
With a Microsoft compiler[1], static variables that are not int-like can also be defined in a header file, but outside of the class declaration, using the Microsoft specific __declspec(selectany).
class A
{
static B b;
}
__declspec(selectany) A::b;
Note that I'm not saying this is good, I just say it can be done.
[1] These days, more compilers than MSC support __declspec(selectany) - at least gcc and clang. Maybe even more.
int foo::i = 0;
Is the correct syntax for initializing the variable, but it must go in the source file (.cpp) rather than in the header.
Because it is a static variable the compiler needs to create only one copy of it. You have to have a line "int foo:i" some where in your code to tell the compiler where to put it otherwise you get a link error. If that is in a header you will get a copy in every file that includes the header, so get multiply defined symbol errors from the linker.
If you want to initialize some compound type (f.e. string) you can do something like that:
class SomeClass {
static std::list<string> _list;
public:
static const std::list<string>& getList() {
struct Initializer {
Initializer() {
// Here you may want to put mutex
_list.push_back("FIRST");
_list.push_back("SECOND");
....
}
}
static Initializer ListInitializationGuard;
return _list;
}
};
As the ListInitializationGuard is a static variable inside SomeClass::getList() method it will be constructed only once, which means that constructor is called once. This will initialize _list variable to value you need. Any subsequent call to getList will simply return already initialized _list object.
Of course you have to access _list object always by calling getList() method.
C++11 static constructor pattern that works for multiple objects
One idiom was proposed at: https://stackoverflow.com/a/27088552/895245 but here goes a cleaner version that does not require creating a new method per member.
main.cpp
#include <cassert>
#include <vector>
// Normally on the .hpp file.
class MyClass {
public:
static std::vector<int> v, v2;
static struct StaticConstructor {
StaticConstructor() {
v.push_back(1);
v.push_back(2);
v2.push_back(3);
v2.push_back(4);
}
} _staticConstructor;
};
// Normally on the .cpp file.
std::vector<int> MyClass::v;
std::vector<int> MyClass::v2;
// Must come after every static member.
MyClass::StaticConstructor MyClass::_staticConstructor;
int main() {
assert(MyClass::v[0] == 1);
assert(MyClass::v[1] == 2);
assert(MyClass::v2[0] == 3);
assert(MyClass::v2[1] == 4);
}
GitHub upstream.
Compile and run:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
See also: static constructors in C++? I need to initialize private static objects
Tested on Ubuntu 19.04.
C++17 inline variable
Mentioned at: https://stackoverflow.com/a/45062055/895245 but here is a multifile runnable example to make it even clearer: How do inline variables work?
This awesome C++17 feature allow us to:
conveniently use just a single memory address for each constant
store it as a constexpr: How to declare constexpr extern?
do it in a single line from one header
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return ¬main_i;
}
Compile and run:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub upstream.
I don't have enough rep here to add this as a comment, but IMO it's good style to write your headers with #include guards anyway, which as noted by Paranaix a few hours ago would prevent a multiple-definition error. Unless you're already using a separate CPP file, it's not necessary to use one just to initialize static non-integral members.
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo
{
private:
static bar i;
};
bar foo::i = VALUE;
#endif
I see no need to use a separate CPP file for this. Sure, you can, but there's no technical reason why you should have to.
You can also include the assignment in the header file if you use header guards. I have used this technique for a C++ library I have created. Another way to achieve the same result is to use static methods. For example...
class Foo
{
public:
int GetMyStatic() const
{
return *MyStatic();
}
private:
static int* MyStatic()
{
static int mStatic = 0;
return &mStatic;
}
}
The above code has the "bonus" of not requiring a CPP/source file. Again, a method I use for my C++ libraries.
The linker problem you encountered is probably caused by:
Providing both class and static member definition in header file,
Including this header in two or more source files.
This is a common problem for those who starts with C++. Static class member must be initialized in single translation unit i.e. in single source file.
Unfortunately, the static class member must be initialized outside of the class body. This complicates writing header-only code, and, therefore, I am using quite different approach. You can provide your static object through static or non-static class function for example:
class Foo
{
// int& getObjectInstance() const {
static int& getObjectInstance() {
static int object;
return object;
}
void func() {
int &object = getValueInstance();
object += 5;
}
};
I follow the idea from Karl. I like it and now I use it as well.
I've changed a little bit the notation and add some functionality
#include <stdio.h>
class Foo
{
public:
int GetMyStaticValue () const { return MyStatic(); }
int & GetMyStaticVar () { return MyStatic(); }
static bool isMyStatic (int & num) { return & num == & MyStatic(); }
private:
static int & MyStatic ()
{
static int mStatic = 7;
return mStatic;
}
};
int main (int, char **)
{
Foo obj;
printf ("mystatic value %d\n", obj.GetMyStaticValue());
obj.GetMyStaticVar () = 3;
printf ("mystatic value %d\n", obj.GetMyStaticValue());
int valMyS = obj.GetMyStaticVar ();
int & iPtr1 = obj.GetMyStaticVar ();
int & iPtr2 = valMyS;
printf ("is my static %d %d\n", Foo::isMyStatic(iPtr1), Foo::isMyStatic(iPtr2));
}
this outputs
mystatic value 7
mystatic value 3
is my static 1 0
Also working in privateStatic.cpp file :
#include <iostream>
using namespace std;
class A
{
private:
static int v;
};
int A::v = 10; // possible initializing
int main()
{
A a;
//cout << A::v << endl; // no access because of private scope
return 0;
}
// g++ privateStatic.cpp -o privateStatic && ./privateStatic
What about a set_default() method?
class foo
{
public:
static void set_default(int);
private:
static int i;
};
void foo::set_default(int x) {
i = x;
}
We would only have to use the set_default(int x) method and our static variable would be initialized.
This would not be in disagreement with the rest of the comments, actually it follows the same principle of initializing the variable in a global scope, but by using this method we make it explicit (and easy to see-understand) instead of having the definition of the variable hanging there.
One "old-school" way to define constants is to replace them by a enum:
class foo
{
private:
enum {i = 0}; // default type = int
enum: int64_t {HUGE = 1000000000000}; // may specify another type
};
This way doesn't require providing a definition, and avoids making the constant lvalue, which can save you some headaches, e.g. when you accidentally ODR-use it.
Here are all possibilities and errors in one simple example ...
#ifndef Foo_h
#define Foo_h
class Foo
{
static const int a = 42; // OK
static const int b {7}; // OK
//static int x = 42; // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
//static int y {7}; // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
static int x;
static int y;
int m = 42;
int n {7};
};
// Foo::x = 42; // error: 'int Foo::x' is private
int Foo::x = 42; // OK in Foo.h if included in only one *.cpp -> *.o file!
int Foo::y {7}; // OK
// int Foo::y {7}; // error: redefinition of 'int Foo::y'
// ONLY if the compiler can see both declarations at the same time it,
// OTHERWISE you get a linker error
#endif // Foo_h
But better place this in Foo.cpp. This way you can separately compile each file and link them later, otherwise Foo:x will be present in multiple object files and cause a linker error. ...
// Foo::x = 42; // error: 'int Foo::x' is private, bad if Foo::X is public!
int Foo::x = 42; // OK in Foo.h if included in only one *.cpp -> *.o file!
int Foo::y {7}; // OK
Does this serves your purpose?
//header file
struct MyStruct {
public:
const std::unordered_map<std::string, uint32_t> str_to_int{
{ "a", 1 },
{ "b", 2 },
...
{ "z", 26 }
};
const std::unordered_map<int , std::string> int_to_str{
{ 1, "a" },
{ 2, "b" },
...
{ 26, "z" }
};
std::string some_string = "justanotherstring";
uint32_t some_int = 42;
static MyStruct & Singleton() {
static MyStruct instance;
return instance;
}
private:
MyStruct() {};
};
//Usage in cpp file
int main(){
std::cout<<MyStruct::Singleton().some_string<<std::endl;
std::cout<<MyStruct::Singleton().some_int<<std::endl;
return 0;
}
I just wanted to mention something a little strange to me when I first encountered this.
I needed to initialize a private static data member in a template class.
in the .h or .hpp, it looks something like this to initialize a static data member of a template class:
template<typename T>
Type ClassName<T>::dataMemberName = initialValue;
So I have a class which has mostly static stuff because it needs to be a library accessible at all times with no instantiation. Anyway, this class has a public static member, a structure called cfg, which contains all of its configuration parameters (mostly boundaries and tolerances for the algorithms implemented by its static methods). And on top it has a const static member, which is a structure of the same type as cfg, but has all the default / usual values for the parameters. Users of my module may load it, modify it in part, and apply it as cfg, or use it as reference, or what do I know.
Now I can't seem to initialize this guy, at all. With no instantiation (and it being static) initialization won't happen in a constructor (there is none anyway). In-class init returns an error, init in the cpp returns a declaration conflict. What's the way forward here ?
Here an example with exact same behavior as I get :
module.h :
#ifndef MODULE_H
#define MODULE_H
typedef struct {
float param1;
float param2;
} module_cfg;
class module
{
public:
module();
static module_cfg cfg;
const static module_cfg default_cfg;
};
#endif // MODULE_H
module.cpp :
#include "module.h"
using namespace std;
module_cfg module::default_cfg = {15, 19};
int main(int argc, char* argv[])
{
//clog << "Hello World!" << endl << endl;
return 0;
}
module::module()
{
}
Errors with above :
module.cpp:11:20: error: conflicting declaration 'module_cfg module::default_cfg'
module_cfg module::default_cfg = {15, 19};
^
In file included from module.cpp:8:0:
module.h:14:29: error: 'module::default_cfg' has a previous declaration as 'const module_cfg module::default_cfg'
const static module_cfg default_cfg;
^
Makefile.Debug:119: recipe for target 'debug/module.o' failed
module.cpp:11:20: error: declaration of 'const module_cfg module::default_cfg' outside of class is not definition [-fpermissive]
module_cfg module::default_cfg = {15, 19};
Thanks in advance,
Charles
The errors above are due to the fact that you are inadvertently redeclaring default_cfg to be mutable in the cpp file.
adding const to the definition fixes it:
const module_cfg module::default_cfg = {15, 19};
I'm still working on getting my first template to work in C++. I'm creating a probability class that contains a template method for calculating the average of a given array. I have this template set up such that the array type and size are flexible.
However, I keep getting a compiler error stating that the array type is not being specified.... which has got me thinking 'Well duh'. I can't seem to fix this issue. I'm not sure whether or not I have a compiler setting misconfigured, or if I'm a missing a semicolon somewhere.
My code is posted below:
Probability Header
#ifndef COFFEEDEVMATH_PROBABILITY_H
#define COFFEEDEVMATH_PROBABILITY_H
class Probability
{
public:
Probability(void);
template <typename T, std::size_t N>
void ExpectedValueDataSet(const std::array<T, N>& data)
{
// Do nothing (place holder)
}
protected:
private:
};
#endif // COFFEEDEVMATH_PROBABILITY_H
Main
#include <iostream>
#include <Probability.h>
int main()
{
std::array<float, 4> hoor = {4, 4, 1, 1};
Probability prob;
//prob.ExpectedValueDataSet(hoor);
}
Just put a #include<array> directive in the file header and, for the sake of clarity, in the main.cpp (even if the second one wouldn't be strictly necessary in this case).
I've got a situation which can be summarized in the following:
class Test
{
Test();
int MySet[10];
};
is it possible to initialize MySet in an initializer list?
Like this kind of initializer list:
Test::Test() : MySet({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {}
Is there any way to initialize a constant-sized member array in a class's initalizer list?
While not available in C++03, C++11 introduces extended initializer lists. You can indeed do it if using a compiler compliant with the C++11 standard.
struct Test {
Test() : set { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } { };
int set[10];
};
The above code compiles fine using g++ -std=c++0x -c test.cc.
As pointed out below me by a helpful user in the comments, this code does not compile using Microsoft's VC++ compiler, cl. Perhaps someone can tell me if the equivalent using std::array will?
#include <array>
struct Test {
Test() : set { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } } { };
std::array<int, 10> set;
};
This also compiles fine using g++ -std=c++0x -c test.cc.
Unfortunately, in C++03, you cannot initialize arrays in initializer lists. You can in C++11 though if your compiler is newer :)
see: How do I initialize a member array with an initializer_list?
"I understand that Set is just a pointer to the static array of 10 integers"
No, that's wrong: it's an array, not a pointer.
You can still initialize it in the constructor's initializer list.
For a compiler that doesn't support C++11 curly braces initialization (Visual C++ version 11 and earlier comes to mind) you'll have to jump through some hoops though, as shown below:
#include <iostream>
#include <vector>
using namespace std;
#define CPP11
#if defined( _MSC_VER )
# if (_MSC_VER <= 1700)
# undef CPP11
# endif
#endif
#ifdef CPP11
class Cpp11
{
private:
int set_[10];
public:
Cpp11()
: set_{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
{}
int foo() const { return set_[3]; }
};
#endif
class Cpp03
{
private:
struct IntArray10 { int values[10]; };
IntArray10 set_;
static IntArray10 const& oneToTen()
{
static IntArray10 const values =
{ {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} };
return values;
}
public:
Cpp03()
: set_( oneToTen() )
{}
int foo() const { return set_.values[3]; }
};
int main()
{}
Instead of using raw arrays, though, use std::vector and C+++11 std::array, both of which are supported even by Visual C++ 11.
I have just found out that the following is not valid.
//Header File
class test
{
const static char array[] = { '1', '2', '3' };
};
Where is the best place to initialize this?
The best place would be in a source file
// Header file
class test
{
const static char array[];
};
// Source file
const char test::array[] = {'1','2','3'};
You can initialize integer types in the class declaration like you tried to do; all other types have to be initialized outside the class declaration, and only once.
You can always do the following:
class test {
static const char array(int index) {
static const char a[] = {'1','2','3'};
return a[index];
}
};
A couple nice things about this paradigm:
No need for a cpp file
You can do range checking if you want to
You avoid having to worry about the static initialization fiasco
//Header File
class test
{
const static char array[];
};
// .cpp
const char test::array[] = { '1', '2', '3' };
Now, in C++17, you can use inline variable
How do inline variables work?
A simple static data member(N4424):
struct WithStaticDataMember {
// This is a definition, no outofline definition is required.
static inline constexpr const char *kFoo = "foo bar";
};
In your example:
//Header File
class test
{
inline constexpr static char array[] = { '1', '2', '3' };
};
should just work
With constexpr you must define the value on the header even in C++11
If you use constexpr instead of const, then this answer suggests that you not only can, but must, define on header even in C++11:
#include <cassert>
struct MyClass {
static constexpr int is[] = {1, 2, 3};
static constexpr int i = 1;
};
// TODO is this ever mandatory? Create example that fails on -std=c++11.
// Pretty sure never mandatory in C++17 https://stackoverflow.com/a/40959093/895245
// constexpr int MyClass::is[];
int main (void) {
assert(MyClass::is[0] == 1);
assert(&MyClass::is[0] == &MyClass::is[1] - 1);
assert(MyClass::i == 1);
assert(&MyClass::i == &MyClass::i);
}
Compile and run with:
g++-10 -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
If instead you try:
struct MyClass {
static constexpr int is[];
};
constexpr int MyClass::is[] = {1, 2, 3};
compilation fails with:
main.cpp:4:26: error: ‘constexpr’ static data member ‘is’ must have an initializer
Tested on Ubuntu 20.04.
This is kind of an abuse of the system, but if you REALLY want to define it in the header file (and you don't have C++17), you can do this. It won't be a static member, but it will be a constant that only takes up storage per compilation unit (rather than per class instance):
(Put all of this code in the header file.)
namespace {
const char test_init_array[] = {'1', '2', '3'};
}
class test {
public:
const char * const array;
test() : array(test_init_array) {}
};